mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
a48e284317
There were some fixes back on March 13th, 2014 for fixing compiling on MIPS64. Also some fixes on June 25th, 2014 for SPARC64 fixes. Probably more things, but those are what I care about.
418 lines
11 KiB
C
418 lines
11 KiB
C
/**
|
|
* \file pkcs5.c
|
|
*
|
|
* \brief PKCS#5 functions
|
|
*
|
|
* \author Mathias Olsson <mathias@kompetensum.com>
|
|
*
|
|
* Copyright (C) 2006-2014, Brainspark B.V.
|
|
*
|
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* PKCS#5 includes PBKDF2 and more
|
|
*
|
|
* http://tools.ietf.org/html/rfc2898 (Specification)
|
|
* http://tools.ietf.org/html/rfc6070 (Test vectors)
|
|
*/
|
|
|
|
#if !defined(POLARSSL_CONFIG_FILE)
|
|
#include "polarssl/config.h"
|
|
#else
|
|
#include POLARSSL_CONFIG_FILE
|
|
#endif
|
|
|
|
#if defined(POLARSSL_PKCS5_C)
|
|
|
|
#include "polarssl/pkcs5.h"
|
|
#include "polarssl/asn1.h"
|
|
#include "polarssl/cipher.h"
|
|
#include "polarssl/oid.h"
|
|
|
|
#if defined(POLARSSL_PLATFORM_C)
|
|
#include "polarssl/platform.h"
|
|
#else
|
|
#define polarssl_printf printf
|
|
#endif
|
|
|
|
static int pkcs5_parse_pbkdf2_params( const asn1_buf *params,
|
|
asn1_buf *salt, int *iterations,
|
|
int *keylen, md_type_t *md_type )
|
|
{
|
|
int ret;
|
|
asn1_buf prf_alg_oid;
|
|
unsigned char *p = params->p;
|
|
const unsigned char *end = params->p + params->len;
|
|
|
|
if( params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
|
|
POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
|
|
/*
|
|
* PBKDF2-params ::= SEQUENCE {
|
|
* salt OCTET STRING,
|
|
* iterationCount INTEGER,
|
|
* keyLength INTEGER OPTIONAL
|
|
* prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
|
|
* }
|
|
*
|
|
*/
|
|
if( ( ret = asn1_get_tag( &p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
|
|
salt->p = p;
|
|
p += salt->len;
|
|
|
|
if( ( ret = asn1_get_int( &p, end, iterations ) ) != 0 )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
|
|
if( p == end )
|
|
return( 0 );
|
|
|
|
if( ( ret = asn1_get_int( &p, end, keylen ) ) != 0 )
|
|
{
|
|
if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
}
|
|
|
|
if( p == end )
|
|
return( 0 );
|
|
|
|
if( ( ret = asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
|
|
if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) )
|
|
return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
|
|
|
*md_type = POLARSSL_MD_SHA1;
|
|
|
|
if( p != end )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
|
|
POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
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 )
|
|
{
|
|
int ret, iterations = 0, keylen = 0;
|
|
unsigned char *p, *end;
|
|
asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
|
|
asn1_buf salt;
|
|
md_type_t md_type = POLARSSL_MD_SHA1;
|
|
unsigned char key[32], iv[32];
|
|
size_t olen = 0;
|
|
const md_info_t *md_info;
|
|
const cipher_info_t *cipher_info;
|
|
md_context_t md_ctx;
|
|
cipher_type_t cipher_alg;
|
|
cipher_context_t cipher_ctx;
|
|
|
|
p = pbe_params->p;
|
|
end = p + pbe_params->len;
|
|
|
|
/*
|
|
* PBES2-params ::= SEQUENCE {
|
|
* keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
|
|
* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
|
|
* }
|
|
*/
|
|
if( pbe_params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
|
|
POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
|
|
|
|
if( ( ret = asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
|
|
// Only PBKDF2 supported at the moment
|
|
//
|
|
if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) )
|
|
return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
|
|
|
if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params,
|
|
&salt, &iterations, &keylen,
|
|
&md_type ) ) != 0 )
|
|
{
|
|
return( ret );
|
|
}
|
|
|
|
md_info = md_info_from_type( md_type );
|
|
if( md_info == NULL )
|
|
return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
|
|
|
if( ( ret = asn1_get_alg( &p, end, &enc_scheme_oid,
|
|
&enc_scheme_params ) ) != 0 )
|
|
{
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
|
|
}
|
|
|
|
if( oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 )
|
|
return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
|
|
|
cipher_info = cipher_info_from_type( cipher_alg );
|
|
if( cipher_info == NULL )
|
|
return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
|
|
|
|
/*
|
|
* The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
|
|
* since it is optional and we don't know if it was set or not
|
|
*/
|
|
keylen = cipher_info->key_length / 8;
|
|
|
|
if( enc_scheme_params.tag != ASN1_OCTET_STRING ||
|
|
enc_scheme_params.len != cipher_info->iv_size )
|
|
{
|
|
return( POLARSSL_ERR_PKCS5_INVALID_FORMAT );
|
|
}
|
|
|
|
md_init( &md_ctx );
|
|
cipher_init( &cipher_ctx );
|
|
|
|
memcpy( iv, enc_scheme_params.p, enc_scheme_params.len );
|
|
|
|
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
|
|
goto exit;
|
|
|
|
if( ( ret = pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len,
|
|
iterations, keylen, key ) ) != 0 )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 )
|
|
goto exit;
|
|
|
|
if( ( ret = cipher_setkey( &cipher_ctx, key, 8 * keylen, mode ) ) != 0 )
|
|
goto exit;
|
|
|
|
if( ( ret = cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len,
|
|
data, datalen, output, &olen ) ) != 0 )
|
|
ret = POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH;
|
|
|
|
exit:
|
|
md_free( &md_ctx );
|
|
cipher_free( &cipher_ctx );
|
|
|
|
return( ret );
|
|
}
|
|
|
|
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 )
|
|
{
|
|
int ret, j;
|
|
unsigned int i;
|
|
unsigned char md1[POLARSSL_MD_MAX_SIZE];
|
|
unsigned char work[POLARSSL_MD_MAX_SIZE];
|
|
unsigned char md_size = md_get_size( ctx->md_info );
|
|
size_t use_len;
|
|
unsigned char *out_p = output;
|
|
unsigned char counter[4];
|
|
|
|
memset( counter, 0, 4 );
|
|
counter[3] = 1;
|
|
|
|
if( iteration_count > 0xFFFFFFFF )
|
|
return( POLARSSL_ERR_PKCS5_BAD_INPUT_DATA );
|
|
|
|
while( key_length )
|
|
{
|
|
// U1 ends up in work
|
|
//
|
|
if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = md_hmac_update( ctx, salt, slen ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = md_hmac_update( ctx, counter, 4 ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = md_hmac_finish( ctx, work ) ) != 0 )
|
|
return( ret );
|
|
|
|
memcpy( md1, work, md_size );
|
|
|
|
for( i = 1; i < iteration_count; i++ )
|
|
{
|
|
// U2 ends up in md1
|
|
//
|
|
if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = md_hmac_update( ctx, md1, md_size ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = md_hmac_finish( ctx, md1 ) ) != 0 )
|
|
return( ret );
|
|
|
|
// U1 xor U2
|
|
//
|
|
for( j = 0; j < md_size; j++ )
|
|
work[j] ^= md1[j];
|
|
}
|
|
|
|
use_len = ( key_length < md_size ) ? key_length : md_size;
|
|
memcpy( out_p, work, use_len );
|
|
|
|
key_length -= (uint32_t) use_len;
|
|
out_p += use_len;
|
|
|
|
for( i = 4; i > 0; i-- )
|
|
if( ++counter[i - 1] != 0 )
|
|
break;
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
#if defined(POLARSSL_SELF_TEST)
|
|
|
|
#if !defined(POLARSSL_SHA1_C)
|
|
int pkcs5_self_test( int verbose )
|
|
{
|
|
if( verbose != 0 )
|
|
polarssl_printf( " PBKDF2 (SHA1): skipped\n\n" );
|
|
|
|
return( 0 );
|
|
}
|
|
#else
|
|
|
|
#include <stdio.h>
|
|
|
|
#define MAX_TESTS 6
|
|
|
|
size_t plen[MAX_TESTS] =
|
|
{ 8, 8, 8, 8, 24, 9 };
|
|
|
|
unsigned char password[MAX_TESTS][32] =
|
|
{
|
|
"password",
|
|
"password",
|
|
"password",
|
|
"password",
|
|
"passwordPASSWORDpassword",
|
|
"pass\0word",
|
|
};
|
|
|
|
size_t slen[MAX_TESTS] =
|
|
{ 4, 4, 4, 4, 36, 5 };
|
|
|
|
unsigned char salt[MAX_TESTS][40] =
|
|
{
|
|
"salt",
|
|
"salt",
|
|
"salt",
|
|
"salt",
|
|
"saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
|
"sa\0lt",
|
|
};
|
|
|
|
uint32_t it_cnt[MAX_TESTS] =
|
|
{ 1, 2, 4096, 16777216, 4096, 4096 };
|
|
|
|
uint32_t key_len[MAX_TESTS] =
|
|
{ 20, 20, 20, 20, 25, 16 };
|
|
|
|
|
|
unsigned char result_key[MAX_TESTS][32] =
|
|
{
|
|
{ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
|
|
0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
|
|
0x2f, 0xe0, 0x37, 0xa6 },
|
|
{ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
|
|
0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
|
|
0xd8, 0xde, 0x89, 0x57 },
|
|
{ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
|
|
0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
|
|
0x65, 0xa4, 0x29, 0xc1 },
|
|
{ 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
|
|
0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
|
|
0x26, 0x34, 0xe9, 0x84 },
|
|
{ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
|
|
0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
|
|
0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
|
|
0x38 },
|
|
{ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
|
|
0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
|
|
};
|
|
|
|
int pkcs5_self_test( int verbose )
|
|
{
|
|
md_context_t sha1_ctx;
|
|
const md_info_t *info_sha1;
|
|
int ret, i;
|
|
unsigned char key[64];
|
|
|
|
md_init( &sha1_ctx );
|
|
|
|
info_sha1 = md_info_from_type( POLARSSL_MD_SHA1 );
|
|
if( info_sha1 == NULL )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
if( ( ret = md_init_ctx( &sha1_ctx, info_sha1 ) ) != 0 )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
polarssl_printf( " PBKDF2 note: test #3 may be slow!\n" );
|
|
|
|
for( i = 0; i < MAX_TESTS; i++ )
|
|
{
|
|
if( verbose != 0 )
|
|
polarssl_printf( " PBKDF2 (SHA1) #%d: ", i );
|
|
|
|
ret = pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i],
|
|
slen[i], it_cnt[i], key_len[i], key );
|
|
if( ret != 0 ||
|
|
memcmp( result_key[i], key, key_len[i] ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
polarssl_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
polarssl_printf( "passed\n" );
|
|
}
|
|
|
|
polarssl_printf( "\n" );
|
|
|
|
exit:
|
|
md_free( &sha1_ctx );
|
|
|
|
return( 0 );
|
|
}
|
|
#endif /* POLARSSL_SHA1_C */
|
|
|
|
#endif /* POLARSSL_SELF_TEST */
|
|
|
|
#endif /* POLARSSL_PKCS5_C */
|