Skip to content

Commit c58a9ba

Browse files
committed
Add support for more algos of encrypted PEM files
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent b959354 commit c58a9ba

File tree

101 files changed

+1775
-253
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+1775
-253
lines changed

src/headers/tomcrypt_private.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,23 @@ int base64_encode_pem(const unsigned char *in, unsigned long inlen,
255255
/* PEM related */
256256

257257
#ifdef LTC_PEM
258+
enum cipher_mode {
259+
cm_none, cm_cbc, cm_cfb, cm_ctr, cm_ofb, cm_stream, cm_gcm
260+
};
261+
258262
struct password {
259263
/* usually a `char*` but could also contain binary data
260264
* so use a `void*` + length to be on the safe side.
261265
*/
262266
void *pw;
263267
unsigned long l;
264268
};
265-
struct dek_info {
266-
const char *alg;
269+
270+
struct blockcipher_info {
271+
const char *name;
272+
const char *algo;
267273
unsigned long keylen;
274+
enum cipher_mode mode;
268275
/* should use `MAXBLOCKSIZE` here, but all supported
269276
* blockciphers require max 16 bytes IV */
270277
char iv[16 * 2 + 1];
@@ -280,11 +287,6 @@ struct str {
280287
#define COPY_STR(n, s, l) do { XMEMCPY(n.p, s, l); n.len = l; } while(0)
281288
#define RESET_STR(n) do { n.p = NULL; n.len = 0; } while(0)
282289

283-
struct dek_info_from_str {
284-
const struct str id;
285-
struct dek_info info;
286-
};
287-
288290
enum more_headers {
289291
no,
290292
yes,
@@ -303,7 +305,7 @@ struct pem_header_id {
303305
struct pem_headers {
304306
const struct pem_header_id *id;
305307
int encrypted;
306-
struct dek_info info;
308+
struct blockcipher_info info;
307309
struct password *pw;
308310
};
309311

@@ -338,6 +340,11 @@ int pbes_decrypt(const pbes_arg *arg, unsigned char *dec_data, unsigned long *d
338340
int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res);
339341
int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
340342

343+
int pem_decrypt(unsigned char *data, unsigned long *datalen,
344+
unsigned char *key, unsigned long keylen,
345+
unsigned char *iv, unsigned long ivlen,
346+
const struct blockcipher_info *info,
347+
enum padding_type padding);
341348
#ifndef LTC_NO_FILE
342349
int pem_get_char_from_file(struct get_char *g);
343350
#endif /* LTC_NO_FILE */

src/misc/pem/pem.c

Lines changed: 153 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,164 @@ const struct pem_header_id pem_std_headers[] = {
4747
};
4848
const unsigned long pem_std_headers_num = sizeof(pem_std_headers)/sizeof(pem_std_headers[0]);
4949

50-
5150
/* Encrypted PEM files */
5251
const struct str pem_proc_type_encrypted = { SET_CSTR(, "Proc-Type: 4,ENCRYPTED") };
5352
const struct str pem_dek_info_start = { SET_CSTR(, "DEK-Info: ") };
54-
const struct dek_info_from_str pem_dek_infos[] =
53+
const struct blockcipher_info pem_dek_infos[] =
5554
{
56-
{ SET_CSTR(.id, "AES-128-CBC,"), .info.alg = "aes", .info.keylen = 128 / 8, },
57-
{ SET_CSTR(.id, "AES-192-CBC,"), .info.alg = "aes", .info.keylen = 192 / 8, },
58-
{ SET_CSTR(.id, "AES-256-CBC,"), .info.alg = "aes", .info.keylen = 256 / 8, },
59-
{ SET_CSTR(.id, "CAMELLIA-128-CBC,"), .info.alg = "camellia", .info.keylen = 128 / 8, },
60-
{ SET_CSTR(.id, "CAMELLIA-192-CBC,"), .info.alg = "camellia", .info.keylen = 192 / 8, },
61-
{ SET_CSTR(.id, "CAMELLIA-256-CBC,"), .info.alg = "camellia", .info.keylen = 256 / 8, },
62-
{ SET_CSTR(.id, "DES-EDE3-CBC,"), .info.alg = "3des", .info.keylen = 192 / 8, },
63-
{ SET_CSTR(.id, "DES-CBC,"), .info.alg = "des", .info.keylen = 64 / 8, },
55+
{ .name = "AES-128-CBC,", .algo = "aes", .keylen = 128 / 8, .mode = cm_cbc, },
56+
{ .name = "AES-192-CBC,", .algo = "aes", .keylen = 192 / 8, .mode = cm_cbc, },
57+
{ .name = "AES-256-CBC,", .algo = "aes", .keylen = 256 / 8, .mode = cm_cbc, },
58+
{ .name = "AES-128-CFB,", .algo = "aes", .keylen = 128 / 8, .mode = cm_cfb, },
59+
{ .name = "AES-192-CFB,", .algo = "aes", .keylen = 192 / 8, .mode = cm_cfb, },
60+
{ .name = "AES-256-CFB,", .algo = "aes", .keylen = 256 / 8, .mode = cm_cfb, },
61+
{ .name = "AES-128-CTR,", .algo = "aes", .keylen = 128 / 8, .mode = cm_ctr, },
62+
{ .name = "AES-192-CTR,", .algo = "aes", .keylen = 192 / 8, .mode = cm_ctr, },
63+
{ .name = "AES-256-CTR,", .algo = "aes", .keylen = 256 / 8, .mode = cm_ctr, },
64+
{ .name = "AES-128-OFB,", .algo = "aes", .keylen = 128 / 8, .mode = cm_ofb, },
65+
{ .name = "AES-192-OFB,", .algo = "aes", .keylen = 192 / 8, .mode = cm_ofb, },
66+
{ .name = "AES-256-OFB,", .algo = "aes", .keylen = 256 / 8, .mode = cm_ofb, },
67+
{ .name = "BF-CBC,", .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cbc, },
68+
{ .name = "BF-CFB,", .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cfb, },
69+
{ .name = "BF-OFB,", .algo = "blowfish", .keylen = 128 / 8, .mode = cm_ofb, },
70+
{ .name = "CAMELLIA-128-CBC,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cbc, },
71+
{ .name = "CAMELLIA-192-CBC,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cbc, },
72+
{ .name = "CAMELLIA-256-CBC,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cbc, },
73+
{ .name = "CAMELLIA-128-CFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cfb, },
74+
{ .name = "CAMELLIA-192-CFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cfb, },
75+
{ .name = "CAMELLIA-256-CFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cfb, },
76+
{ .name = "CAMELLIA-128-CTR,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ctr, },
77+
{ .name = "CAMELLIA-192-CTR,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ctr, },
78+
{ .name = "CAMELLIA-256-CTR,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ctr, },
79+
{ .name = "CAMELLIA-128-OFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ofb, },
80+
{ .name = "CAMELLIA-192-OFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ofb, },
81+
{ .name = "CAMELLIA-256-OFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ofb, },
82+
{ .name = "CAST5-CBC,", .algo = "cast5", .keylen = 128 / 8, .mode = cm_cbc, },
83+
{ .name = "CAST5-CFB,", .algo = "cast5", .keylen = 128 / 8, .mode = cm_cfb, },
84+
{ .name = "CAST5-OFB,", .algo = "cast5", .keylen = 128 / 8, .mode = cm_ofb, },
85+
{ .name = "DES-EDE3-CBC,", .algo = "3des", .keylen = 192 / 8, .mode = cm_cbc, },
86+
{ .name = "DES-EDE3-CFB,", .algo = "3des", .keylen = 192 / 8, .mode = cm_cfb, },
87+
{ .name = "DES-EDE3-OFB,", .algo = "3des", .keylen = 192 / 8, .mode = cm_ofb, },
88+
{ .name = "DES-CBC,", .algo = "des", .keylen = 64 / 8, .mode = cm_cbc, },
89+
{ .name = "DES-CFB,", .algo = "des", .keylen = 64 / 8, .mode = cm_cfb, },
90+
{ .name = "DES-OFB,", .algo = "des", .keylen = 64 / 8, .mode = cm_ofb, },
91+
{ .name = "IDEA-CBC,", .algo = "idea", .keylen = 128 / 8, .mode = cm_cbc, },
92+
{ .name = "IDEA-CFB,", .algo = "idea", .keylen = 128 / 8, .mode = cm_cfb, },
93+
{ .name = "IDEA-OFB,", .algo = "idea", .keylen = 128 / 8, .mode = cm_ofb, },
94+
{ .name = "RC2-40-CBC,", .algo = "rc2", .keylen = 40 / 8, .mode = cm_cbc, },
95+
{ .name = "RC2-64-CBC,", .algo = "rc2", .keylen = 64 / 8, .mode = cm_cbc, },
96+
{ .name = "RC2-CBC,", .algo = "rc2", .keylen = 128 / 8, .mode = cm_cbc, },
97+
{ .name = "RC2-CFB,", .algo = "rc2", .keylen = 128 / 8, .mode = cm_cfb, },
98+
{ .name = "RC2-OFB,", .algo = "rc2", .keylen = 128 / 8, .mode = cm_ofb, },
99+
{ .name = "SEED-CBC,", .algo = "seed", .keylen = 128 / 8, .mode = cm_cbc, },
100+
{ .name = "SEED-CFB,", .algo = "seed", .keylen = 128 / 8, .mode = cm_cfb, },
101+
{ .name = "SEED-OFB,", .algo = "seed", .keylen = 128 / 8, .mode = cm_ofb, },
64102
};
65103
const unsigned long pem_dek_infos_num = sizeof(pem_dek_infos)/sizeof(pem_dek_infos[0]);
66104

105+
int pem_decrypt(unsigned char *data, unsigned long *datalen,
106+
unsigned char *key, unsigned long keylen,
107+
unsigned char *iv, unsigned long ivlen,
108+
const struct blockcipher_info *info,
109+
enum padding_type padding)
110+
{
111+
int err, cipher;
112+
struct {
113+
union {
114+
#ifdef LTC_CBC_MODE
115+
symmetric_CBC cbc;
116+
#endif
117+
#ifdef LTC_CFB_MODE
118+
symmetric_CFB cfb;
119+
#endif
120+
#ifdef LTC_CTR_MODE
121+
symmetric_CTR ctr;
122+
#endif
123+
#ifdef LTC_OFB_MODE
124+
symmetric_OFB ofb;
125+
#endif
126+
} ctx;
127+
} s;
128+
129+
cipher = find_cipher(info->algo);
130+
if (cipher == -1) {
131+
return CRYPT_INVALID_CIPHER;
132+
}
133+
134+
switch (info->mode) {
135+
case cm_cbc:
136+
#ifdef LTC_CBC_MODE
137+
LTC_ARGCHK(ivlen == (unsigned long)cipher_descriptor[cipher].block_length);
138+
139+
if ((err = cbc_start(cipher, iv, key, keylen, 0, &s.ctx.cbc)) != CRYPT_OK) {
140+
goto error_out;
141+
}
142+
if ((err = cbc_decrypt(data, data, *datalen, &s.ctx.cbc)) != CRYPT_OK) {
143+
goto error_out;
144+
}
145+
if ((err = cbc_done(&s.ctx.cbc)) != CRYPT_OK) {
146+
goto error_out;
147+
}
148+
149+
if ((err = padding_depad(data, datalen, padding | s.ctx.cbc.blocklen)) != CRYPT_OK) {
150+
goto error_out;
151+
}
152+
#else
153+
return CRYPT_INVALID_CIPHER;
154+
#endif
155+
break;
156+
case cm_cfb:
157+
#ifdef LTC_CFB_MODE
158+
if ((err = cfb_start(cipher, iv, key, keylen, 0, &s.ctx.cfb)) != CRYPT_OK) {
159+
goto error_out;
160+
}
161+
if ((err = cfb_decrypt(data, data, *datalen, &s.ctx.cfb)) != CRYPT_OK) {
162+
goto error_out;
163+
}
164+
if ((err = cfb_done(&s.ctx.cfb)) != CRYPT_OK) {
165+
goto error_out;
166+
}
167+
#else
168+
return CRYPT_INVALID_CIPHER;
169+
#endif
170+
break;
171+
case cm_ctr:
172+
#ifdef LTC_CTR_MODE
173+
if ((err = ctr_start(cipher, iv, key, keylen, 0, CTR_COUNTER_BIG_ENDIAN, &s.ctx.ctr)) != CRYPT_OK) {
174+
goto error_out;
175+
}
176+
if ((err = ctr_decrypt(data, data, *datalen, &s.ctx.ctr)) != CRYPT_OK) {
177+
goto error_out;
178+
}
179+
if ((err = ctr_done(&s.ctx.ctr)) != CRYPT_OK) {
180+
goto error_out;
181+
}
182+
#else
183+
return CRYPT_INVALID_CIPHER;
184+
#endif
185+
break;
186+
case cm_ofb:
187+
#ifdef LTC_OFB_MODE
188+
if ((err = ofb_start(cipher, iv, key, keylen, 0, &s.ctx.ofb)) != CRYPT_OK) {
189+
goto error_out;
190+
}
191+
if ((err = ofb_decrypt(data, data, *datalen, &s.ctx.ofb)) != CRYPT_OK) {
192+
goto error_out;
193+
}
194+
if ((err = ofb_done(&s.ctx.ofb)) != CRYPT_OK) {
195+
goto error_out;
196+
}
197+
#else
198+
return CRYPT_INVALID_CIPHER;
199+
#endif
200+
break;
201+
default:
202+
err = CRYPT_INVALID_ARG;
203+
break;
204+
}
205+
206+
error_out:
207+
return err;
208+
}
209+
67210
#endif /* LTC_PEM */

src/misc/pem/pem_pkcs.c

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
1616
{
1717
unsigned char iv[MAXBLOCKSIZE], key[MAXBLOCKSIZE];
1818
unsigned long ivlen, klen;
19-
int err;
20-
symmetric_CBC cbc_ctx;
19+
int err, cipher;
2120

21+
cipher = find_cipher(hdr->info.algo);
22+
if (cipher == -1) {
23+
return CRYPT_INVALID_CIPHER;
24+
}
2225
if (hdr->info.keylen > sizeof(key)) {
2326
return CRYPT_BUFFER_OVERFLOW;
2427
}
@@ -35,20 +38,8 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
3538
return err;
3639
}
3740

38-
if ((err = cbc_start(find_cipher(hdr->info.alg), iv, key, klen, 0, &cbc_ctx)) != CRYPT_OK) {
39-
goto error_out;
40-
}
41-
if ((err = cbc_decrypt(pem, pem, *l, &cbc_ctx)) != CRYPT_OK) {
42-
goto error_out;
43-
}
44-
if ((err = cbc_done(&cbc_ctx)) != CRYPT_OK) {
45-
goto error_out;
46-
}
47-
if ((err = padding_depad(pem, l, LTC_PAD_PKCS7 | cbc_ctx.blocklen)) != CRYPT_OK) {
48-
goto error_out;
49-
}
41+
err = pem_decrypt(pem, l, key, klen, iv, ivlen, &hdr->info, LTC_PAD_PKCS7);
5042

51-
error_out:
5243
zeromem(key, sizeof(key));
5344
zeromem(iv, sizeof(iv));
5445
return err;

src/misc/pem/pem_read.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
extern const struct str pem_proc_type_encrypted;
1313
extern const struct str pem_dek_info_start;
14-
extern const struct dek_info_from_str pem_dek_infos[];
14+
extern const struct blockcipher_info pem_dek_infos[];
1515
extern const unsigned long pem_dek_infos_num;
1616

1717
#ifndef LTC_NO_FILE
@@ -116,21 +116,23 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
116116
hdr->encrypted = 1;
117117
break;
118118
case 2:
119-
hdr->info.alg = NULL;
119+
hdr->info.algo = NULL;
120120
if (XMEMCMP(buf, pem_dek_info_start.p, pem_dek_info_start.len))
121121
return CRYPT_INVALID_PACKET;
122122
alg_start = &buf[pem_dek_info_start.len];
123123
for (n = 0; n < pem_dek_infos_num; ++n) {
124-
if (slen >= pem_dek_infos[n].id.len + pem_dek_info_start.len && !XMEMCMP(alg_start, pem_dek_infos[n].id.p, pem_dek_infos[n].id.len)) {
125-
hdr->info = pem_dek_infos[n].info;
126-
tmplen = XSTRLEN(alg_start + pem_dek_infos[n].id.len);
124+
unsigned long namelen = XSTRLEN(pem_dek_infos[n].name);
125+
if (slen >= namelen + pem_dek_info_start.len && !XMEMCMP(alg_start, pem_dek_infos[n].name, namelen)) {
126+
char *iv = alg_start + namelen;
127+
hdr->info = pem_dek_infos[n];
128+
tmplen = XSTRLEN(iv);
127129
if (tmplen > sizeof(hdr->info.iv))
128130
return CRYPT_INVALID_KEYSIZE;
129-
XMEMCPY(hdr->info.iv, alg_start + pem_dek_infos[n].id.len, tmplen);
131+
XMEMCPY(hdr->info.iv, iv, tmplen);
130132
break;
131133
}
132134
}
133-
if (hdr->info.alg == NULL) {
135+
if (hdr->info.algo == NULL) {
134136
return CRYPT_INVALID_CIPHER;
135137
}
136138
break;

0 commit comments

Comments
 (0)