PolarSSL v1.3.1
pkcs5.c
Go to the documentation of this file.
1 
29 /*
30  * PKCS#5 includes PBKDF2 and more
31  *
32  * http://tools.ietf.org/html/rfc2898 (Specification)
33  * http://tools.ietf.org/html/rfc6070 (Test vectors)
34  */
35 
36 #include "polarssl/config.h"
37 
38 #if defined(POLARSSL_PKCS5_C)
39 
40 #include "polarssl/pkcs5.h"
41 #include "polarssl/asn1.h"
42 #include "polarssl/cipher.h"
43 #include "polarssl/oid.h"
44 
45 static int pkcs5_parse_pbkdf2_params( asn1_buf *params,
46  asn1_buf *salt, int *iterations,
47  int *keylen, md_type_t *md_type )
48 {
49  int ret;
50  asn1_buf prf_alg_oid;
51  unsigned char **p = &params->p;
52  const unsigned char *end = params->p + params->len;
53 
54  if( params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
57  /*
58  * PBKDF2-params ::= SEQUENCE {
59  * salt OCTET STRING,
60  * iterationCount INTEGER,
61  * keyLength INTEGER OPTIONAL
62  * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
63  * }
64  *
65  */
66  if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
67  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
68 
69  salt->p = *p;
70  *p += salt->len;
71 
72  if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 )
73  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
74 
75  if( *p == end )
76  return( 0 );
77 
78  if( ( ret = asn1_get_int( p, end, keylen ) ) != 0 )
79  {
81  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
82  }
83 
84  if( *p == end )
85  return( 0 );
86 
87  if( ( ret = asn1_get_alg_null( p, end, &prf_alg_oid ) ) != 0 )
88  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
89 
90  if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) )
92 
93  *md_type = POLARSSL_MD_SHA1;
94 
95  if( *p != end )
98 
99  return( 0 );
100 }
101 
102 int pkcs5_pbes2( asn1_buf *pbe_params, int mode,
103  const unsigned char *pwd, size_t pwdlen,
104  const unsigned char *data, size_t datalen,
105  unsigned char *output )
106 {
107  int ret, iterations = 0, keylen = 0;
108  unsigned char *p, *end;
109  asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
110  asn1_buf salt;
111  md_type_t md_type = POLARSSL_MD_SHA1;
112  unsigned char key[32], iv[32];
113  size_t olen = 0;
114  const md_info_t *md_info;
115  const cipher_info_t *cipher_info;
116  md_context_t md_ctx;
117  cipher_type_t cipher_alg;
118  cipher_context_t cipher_ctx;
119 
120  p = pbe_params->p;
121  end = p + pbe_params->len;
122 
123  memset( &md_ctx, 0, sizeof(md_context_t) );
124  memset( &cipher_ctx, 0, sizeof(cipher_context_t) );
125 
126  /*
127  * PBES2-params ::= SEQUENCE {
128  * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
129  * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
130  * }
131  */
132  if( pbe_params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
135 
136  if( ( ret = asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
137  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
138 
139  // Only PBKDF2 supported at the moment
140  //
141  if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) )
143 
144  if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params,
145  &salt, &iterations, &keylen,
146  &md_type ) ) != 0 )
147  {
148  return( ret );
149  }
150 
151  md_info = md_info_from_type( md_type );
152  if( md_info == NULL )
154 
155  if( ( ret = asn1_get_alg( &p, end, &enc_scheme_oid, &enc_scheme_params ) ) != 0 )
156  return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
157 
158  if ( oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 )
160 
161  cipher_info = cipher_info_from_type( cipher_alg );
162  if( cipher_info == NULL )
164 
165  keylen = cipher_info->key_length / 8;
166 
167  if( enc_scheme_params.tag != ASN1_OCTET_STRING ||
168  enc_scheme_params.len != cipher_info->iv_size )
169  {
171  }
172 
173  memcpy( iv, enc_scheme_params.p, enc_scheme_params.len );
174 
175  if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
176  goto exit;
177 
178  if ( ( ret = pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len,
179  iterations, keylen, key ) ) != 0 )
180  {
181  goto exit;
182  }
183 
184  if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 )
185  goto exit;
186 
187  if( ( ret = cipher_setkey( &cipher_ctx, key, 8 * keylen, mode ) ) != 0 )
188  goto exit;
189 
190  if( ( ret = cipher_set_iv( &cipher_ctx, iv, enc_scheme_params.len ) ) != 0 )
191  goto exit;
192 
193  if( ( ret = cipher_reset( &cipher_ctx ) ) != 0 )
194  goto exit;
195 
196  if( ( ret = cipher_update( &cipher_ctx, data, datalen,
197  output, &olen ) ) != 0 )
198  {
199  goto exit;
200  }
201 
202  if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
204 
205 exit:
206  md_free_ctx( &md_ctx );
207  cipher_free_ctx( &cipher_ctx );
208 
209  return( ret );
210 }
211 
212 int pkcs5_pbkdf2_hmac( md_context_t *ctx, const unsigned char *password,
213  size_t plen, const unsigned char *salt, size_t slen,
214  unsigned int iteration_count,
215  uint32_t key_length, unsigned char *output )
216 {
217  int ret, j;
218  unsigned int i;
219  unsigned char md1[POLARSSL_MD_MAX_SIZE];
220  unsigned char work[POLARSSL_MD_MAX_SIZE];
221  unsigned char md_size = md_get_size( ctx->md_info );
222  size_t use_len;
223  unsigned char *out_p = output;
224  unsigned char counter[4];
225 
226  memset( counter, 0, 4 );
227  counter[3] = 1;
228 
229  if( iteration_count > 0xFFFFFFFF )
231 
232  while( key_length )
233  {
234  // U1 ends up in work
235  //
236  if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 )
237  return( ret );
238 
239  if( ( ret = md_hmac_update( ctx, salt, slen ) ) != 0 )
240  return( ret );
241 
242  if( ( ret = md_hmac_update( ctx, counter, 4 ) ) != 0 )
243  return( ret );
244 
245  if( ( ret = md_hmac_finish( ctx, work ) ) != 0 )
246  return( ret );
247 
248  memcpy( md1, work, md_size );
249 
250  for ( i = 1; i < iteration_count; i++ )
251  {
252  // U2 ends up in md1
253  //
254  if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 )
255  return( ret );
256 
257  if( ( ret = md_hmac_update( ctx, md1, md_size ) ) != 0 )
258  return( ret );
259 
260  if( ( ret = md_hmac_finish( ctx, md1 ) ) != 0 )
261  return( ret );
262 
263  // U1 xor U2
264  //
265  for( j = 0; j < md_size; j++ )
266  work[j] ^= md1[j];
267  }
268 
269  use_len = ( key_length < md_size ) ? key_length : md_size;
270  memcpy( out_p, work, use_len );
271 
272  key_length -= (uint32_t) use_len;
273  out_p += use_len;
274 
275  for( i = 4; i > 0; i-- )
276  if( ++counter[i - 1] != 0 )
277  break;
278  }
279 
280  return( 0 );
281 }
282 
283 #if defined(POLARSSL_SELF_TEST)
284 
285 #include <stdio.h>
286 
287 #define MAX_TESTS 6
288 
289 size_t plen[MAX_TESTS] =
290  { 8, 8, 8, 8, 24, 9 };
291 
292 unsigned char password[MAX_TESTS][32] =
293 {
294  "password",
295  "password",
296  "password",
297  "password",
298  "passwordPASSWORDpassword",
299  "pass\0word",
300 };
301 
302 size_t slen[MAX_TESTS] =
303  { 4, 4, 4, 4, 36, 5 };
304 
305 unsigned char salt[MAX_TESTS][40] =
306 {
307  "salt",
308  "salt",
309  "salt",
310  "salt",
311  "saltSALTsaltSALTsaltSALTsaltSALTsalt",
312  "sa\0lt",
313 };
314 
315 uint32_t it_cnt[MAX_TESTS] =
316  { 1, 2, 4096, 16777216, 4096, 4096 };
317 
318 uint32_t key_len[MAX_TESTS] =
319  { 20, 20, 20, 20, 25, 16 };
320 
321 
322 unsigned char result_key[MAX_TESTS][32] =
323 {
324  { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
325  0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
326  0x2f, 0xe0, 0x37, 0xa6 },
327  { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
328  0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
329  0xd8, 0xde, 0x89, 0x57 },
330  { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
331  0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
332  0x65, 0xa4, 0x29, 0xc1 },
333  { 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
334  0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
335  0x26, 0x34, 0xe9, 0x84 },
336  { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
337  0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
338  0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
339  0x38 },
340  { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
341  0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
342 };
343 
344 int pkcs5_self_test( int verbose )
345 {
346  md_context_t sha1_ctx;
347  const md_info_t *info_sha1;
348  int ret, i;
349  unsigned char key[64];
350 
351  info_sha1 = md_info_from_type( POLARSSL_MD_SHA1 );
352  if( info_sha1 == NULL )
353  return( 1 );
354 
355  if( ( ret = md_init_ctx( &sha1_ctx, info_sha1 ) ) != 0 )
356  return( 1 );
357 
358  for( i = 0; i < MAX_TESTS; i++ )
359  {
360  printf( " PBKDF2 (SHA1) #%d: ", i );
361 
362  ret = pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i],
363  slen[i], it_cnt[i], key_len[i], key );
364  if( ret != 0 ||
365  memcmp( result_key[i], key, key_len[i] ) != 0 )
366  {
367  if( verbose != 0 )
368  printf( "failed\n" );
369 
370  return( 1 );
371  }
372 
373  if( verbose != 0 )
374  printf( "passed\n" );
375  }
376 
377  printf( "\n" );
378 
379  if( ( ret = md_free_ctx( &sha1_ctx ) ) != 0 )
380  return( 1 );
381 
382  return( 0 );
383 }
384 
385 #endif /* POLARSSL_SELF_TEST */
386 
387 #endif /* POLARSSL_PKCS5_C */
#define POLARSSL_ERR_PKCS5_INVALID_FORMAT
Unexpected ASN.1 data.
Definition: pkcs5.h:45
int cipher_finish(cipher_context_t *ctx, unsigned char *output, size_t *olen)
Generic cipher finalisation function.
Generic cipher context.
Definition: cipher.h:233
int pkcs5_self_test(int verbose)
Checkup routine.
PKCS#5 functions.
#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH
Actual length differs from expected length.
Definition: asn1.h:53
Cipher information.
Definition: cipher.h:201
const cipher_info_t * cipher_info_from_type(const cipher_type_t cipher_type)
Returns the cipher information structure associated with the given cipher type.
int asn1_get_int(unsigned char **p, const unsigned char *end, int *val)
Retrieve an integer ASN.1 tag and its value.
int md_init_ctx(md_context_t *ctx, const md_info_t *md_info)
Initialises and fills the message digest context structure with the appropriate values.
#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE
Requested encryption or digest alg not available.
Definition: pkcs5.h:46
#define ASN1_SEQUENCE
Definition: asn1.h:78
Configuration options (set of defines)
#define OID_CMP(oid_str, oid_buf)
Compares two asn1_buf structures for the same OID.
Definition: asn1.h:100
#define ASN1_CONSTRUCTED
Definition: asn1.h:88
static unsigned char md_get_size(const md_info_t *md_info)
Returns the size of the message digest output.
Definition: md.h:205
int pkcs5_pbkdf2_hmac(md_context_t *ctx, const unsigned char *password, size_t plen, const unsigned char *salt, size_t slen, unsigned int iteration_count, uint32_t key_length, unsigned char *output)
PKCS#5 PBKDF2 using HMAC.
Object Identifier (OID) database.
const md_info_t * md_info
Information about the associated message digest.
Definition: md.h:131
md_type_t
Definition: md.h:51
#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH
Given private key password does not allow for correct decryption.
Definition: pkcs5.h:47
const md_info_t * md_info_from_type(md_type_t md_type)
Returns the message digest information associated with the given digest type.
Generic ASN.1 parsing.
cipher_type_t
Definition: cipher.h:75
int pkcs5_pbes2(asn1_buf *pbe_params, int mode, const unsigned char *pwd, size_t pwdlen, const unsigned char *data, size_t datalen, unsigned char *output)
PKCS#5 PBES2 function.
int oid_get_cipher_alg(const asn1_buf *oid, cipher_type_t *cipher_alg)
Translate encryption algorithm OID into cipher_type.
int cipher_free_ctx(cipher_context_t *ctx)
Free the cipher-specific context of ctx.
int asn1_get_alg_null(unsigned char **p, const unsigned char *end, asn1_buf *alg)
Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no params.
unsigned int key_length
Cipher key length, in bits (default length for variable sized ciphers) (Includes parity bits for ciph...
Definition: cipher.h:210
int asn1_get_alg(unsigned char **p, const unsigned char *end, asn1_buf *alg, asn1_buf *params)
Retrieve an AlgorithmIdentifier ASN.1 sequence.
int cipher_set_iv(cipher_context_t *ctx, const unsigned char *iv, size_t iv_len)
Set the initialization vector (IV) or nonce.
int cipher_update(cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen)
Generic cipher update function.
unsigned char * p
ASN1 data, e.g.
Definition: asn1.h:120
Generic cipher wrapper.
int tag
ASN1 type, e.g.
Definition: asn1.h:118
int cipher_reset(cipher_context_t *ctx)
Finish preparation of the given context.
int md_hmac_starts(md_context_t *ctx, const unsigned char *key, size_t keylen)
Generic HMAC context setup.
int cipher_init_ctx(cipher_context_t *ctx, const cipher_info_t *cipher_info)
Initialises and fills the cipher context structure with the appropriate values.
int cipher_setkey(cipher_context_t *ctx, const unsigned char *key, int key_length, const operation_t operation)
Set the key to use with the given context.
Type-length-value structure that allows for ASN1 using DER.
Definition: asn1.h:116
#define OID_PKCS5_PBKDF2
id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
Definition: oid.h:218
size_t len
ASN1 length, e.g.
Definition: asn1.h:119
int md_hmac_update(md_context_t *ctx, const unsigned char *input, size_t ilen)
Generic HMAC process buffer.
#define POLARSSL_MD_MAX_SIZE
Definition: md.h:66
int asn1_get_tag(unsigned char **p, const unsigned char *end, size_t *len, int tag)
Get the tag and length of the tag.
#define ASN1_OCTET_STRING
Definition: asn1.h:74
#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA
Bad input parameters to function.
Definition: pkcs5.h:44
int md_free_ctx(md_context_t *ctx)
Free the message-specific context of ctx.
#define OID_HMAC_SHA1
id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(...
Definition: oid.h:207
Message digest information.
Definition: md.h:73
#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG
ASN1 tag was of an unexpected value.
Definition: asn1.h:51
unsigned int iv_size
IV/NONCE size, in bytes.
Definition: cipher.h:217
int md_hmac_finish(md_context_t *ctx, unsigned char *output)
Generic HMAC final digest.
Generic message digest context.
Definition: md.h:129