pkcs#5 v.20 and pkcs#12 private encryption for pkcs#8 keys

This commit is contained in:
Todd A Ouska
2011-04-14 10:04:24 -07:00
parent 2da2e15484
commit d788030343
13 changed files with 431 additions and 31 deletions

View File

@@ -0,0 +1,11 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBgjAcBgoqhkiG9w0BDAEDMA4ECDkwZMQEXsc8AgIIAASCAWAswojJ2ac33Tak
A8ol6daT+VLEtVwgh9AMO8NE/2xvPZFd3758j/9136k/dsci59ZbvnAVnOURf8Sa
MW0jaE+JnrnEdGDZAuODONGCtKdBx3fntHw6qRYIY0t7yhLCCRdeoVH6XK60JUtS
vzi+Hitvg5ObzV1RpiockVCxGJDAizDrXMgQO7N7doeb9fypoBx5IFgLztWONFAg
A9rQrd5CnkgEbOygRYMduv6fX+uEXWrHEB3vDI6HY5k+VHjx2XLGmNOH1goiv+9p
DA4n4YpN45xRQUDKmx2T6kyULnMoG7Tf/le2qtJ2nja7697yk8zeEkZnR+UD2IXh
/A5eyhAquiM5qDbbV46ydOh2Aji6vI8E8/ZnYk2SJ2/VVlNro/tL0XELYdjBBFnI
SfEtCp1QWWtQdCAPipWzgmsEHKkk4ihmHQqTjmoJ0Pl9XbhxvqHUUrKdHXVJtksZ
TmvgXItk
-----END ENCRYPTED PRIVATE KEY-----

View File

@@ -0,0 +1,11 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIBI6Zodac3rQCAggA
MBQGCCqGSIb3DQMHBAjJZP0y7jYpRwSCAWDKV70/DSueiztJHeMKow93Fd/KXDpU
PGTtlz+lfmOUcGTTt5PwSI2rjHX+QeFTCeb2j9bekcWcaW2iIO8FDRJm1djdKVh0
mO2kAxM0W2s+GoR7T6ByQSrqKp2NL6Ug/B6od2xZ6/0tvcB4Ig+10ljL3/pT3T9M
EYCQ5gjaGhPlJIZhFIwmh6x+Pz+d2bkmXObasKEhwRMhJU9GYhKhWB2fOfl8zWlb
tIDcWBf2rCZUfk3LFx/FrV0NOIY5Jmpm/xQt2gdBIos9LNV16HQOqHkhPBhGXP9D
WZGTrpxgClpZhCUJ+LvqZbAp1dXbfrrElrux0y2zmSGxWP9z8cmfC1SHgBIxcD36
CymYSD0s1hPMH4sFoCM6uyEFfK5KwRpYc3IKfEzvkk9+ZTBYpryzJNDqR1Xpfklp
19m2qz9aJjkIgV4afydQWHYEKVm5IS/PcRVl0ZWkgxJXNHRmLd7HWysS
-----END ENCRYPTED PRIVATE KEY-----

View File

@@ -79,19 +79,28 @@ enum DN_Tags {
};
enum PBES {
PBE_MD5_DES = 0,
PBE_SHA1_DES = 1
PBE_MD5_DES = 0,
PBE_SHA1_DES = 1,
PBE_SHA1_DES3 = 2,
PBE_SHA1_RC4_128 = 3,
PBES2 = 13 /* algo ID */
};
enum ENCRYPTION_TYPES {
DES_TYPE = 0
DES_TYPE = 0,
DES3_TYPE = 1,
RC4_TYPE = 2
};
enum Misc_ASN {
ASN_NAME_MAX = 256,
MAX_SALT_SIZE = 64, /* MAX PKCS Salt length */
MAX_IV_SIZE = 64, /* MAX PKCS Iv length */
MAX_KEY_SIZE = 64, /* MAX PKCS Key length */
PKCS5 = 5, /* PKCS oid tag */
PKCS5v2 = 6, /* PKCS #5 v2.0 */
PKCS12 = 12, /* PKCS #12 */
MAX_UNICODE_SZ = 256,
SHA_SIZE = 20,
RSA_INTS = 8, /* RSA ints in private key */
MIN_DATE_SIZE = 13,
@@ -155,6 +164,11 @@ enum Ecc_Sum {
};
enum KDF_Sum {
PBKDF2_OID = 660
};
/* Certificate file Type */
enum CertType {
CERT_TYPE = 0,

View File

@@ -298,6 +298,7 @@ int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
int mp_2expt (mp_int * a, int b);
int mp_reduce_2k_setup(mp_int *a, mp_digit *d);
int mp_add_d (mp_int* a, mp_digit b, mp_int* c);
/* end support added functions */
/* added */

View File

@@ -39,6 +39,8 @@ int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
int PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt,
int sLen, int iterations, int kLen, int hashType);
int PKCS12_PBKDF(byte* output, const byte* passwd, int pLen, const byte* salt,
int sLen, int iterations, int kLen, int hashType, int purpose);
#ifdef __cplusplus

View File

@@ -620,6 +620,7 @@ int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int*
int mp_add (mp_int * a, mp_int * b, mp_int * c);
int mp_sub (mp_int * a, mp_int * b, mp_int * c);
int mp_add_d (mp_int * a, mp_digit b, mp_int * c);
int mp_mul (mp_int * a, mp_int * b, mp_int * c);
int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);

View File

@@ -519,12 +519,35 @@ int ToTraditional(byte* input, word32 sz)
/* Check To see if PKCS version algo is supported, set id if it is return 0
< 0 on error */
static int CheckAlgo(int version, int algo, int* id)
static int CheckAlgo(int first, int second, int* id, int* version)
{
if (version != PKCS5)
*id = -1;
*version = PKCS5; /* default */
if (first == 1) {
switch (second) {
case 1:
*id = PBE_SHA1_RC4_128;
*version = PKCS12;
return 0;
case 3:
*id = PBE_SHA1_DES3;
*version = PKCS12;
return 0;
default:
return -1;
}
}
if (first != PKCS5)
return ASN_INPUT_E; /* VERSION ERROR */
switch (algo) {
if (second == PBES2) {
*version = PKCS5v2;
return 0;
}
switch (second) {
case 3: /* see RFC 2898 for ids */
*id = PBE_MD5_DES;
return 0;
@@ -538,44 +561,129 @@ static int CheckAlgo(int version, int algo, int* id)
}
/* Check To see if PKCS v2 algo is supported, set id if it is return 0
< 0 on error */
static int CheckAlgoV2(int oid, int* id)
{
switch (oid) {
case 69:
*id = PBE_SHA1_DES;
return 0;
case 652:
*id = PBE_SHA1_DES3;
return 0;
default:
return -1;
}
}
/* Decrypt intput in place from parameters based on id */
static int DecryptKey(const char* password, int passwordSz, byte* salt,
int saltSz, int iterations, int id, byte* input, int length)
int saltSz, int iterations, int id, byte* input,
int length, int version, byte* cbcIv)
{
byte key[MAX_KEY_SIZE];
int hashType;
int derivedLen;
int decryptionType;
int ret = 0;
switch (id) {
case PBE_MD5_DES:
hashType = MD5;
derivedLen = 16;
derivedLen = 16; /* may need iv for v1.5 */
decryptionType = DES_TYPE;
break;
case PBE_SHA1_DES:
hashType = SHA;
derivedLen = 16;
derivedLen = 16; /* may need iv for v1.5 */
decryptionType = DES_TYPE;
break;
case PBE_SHA1_DES3:
hashType = SHA;
derivedLen = 32; /* may need iv for v1.5 */
decryptionType = DES3_TYPE;
break;
case PBE_SHA1_RC4_128:
hashType = SHA;
derivedLen = 16;
decryptionType = RC4_TYPE;
break;
default:
return -1; /* unknown algo id */
}
PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
if (version == PKCS5v2)
ret = PBKDF2(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
else if (version == PKCS5)
ret = PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
else if (version == PKCS12) {
int i, idx = 0;
byte unicodePasswd[MAX_UNICODE_SZ];
if ( (passwordSz * 2 + 2) > sizeof(unicodePasswd))
return -1; /* unicode passwd too big */
for (i = 0; i < passwordSz; i++) {
unicodePasswd[idx++] = 0x00;
unicodePasswd[idx++] = (byte)password[i];
}
/* add trailing NULL */
unicodePasswd[idx++] = 0x00;
unicodePasswd[idx++] = 0x00;
ret = PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
iterations, derivedLen, hashType, 1);
if (decryptionType != RC4_TYPE)
ret += PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
iterations, 8, hashType, 2);
}
if (ret != 0)
return ret;
switch (decryptionType) {
case DES_TYPE:
{
Des dec;
Des_SetKey(&dec, key, key + 8, DES_DECRYPTION);
byte* desIv = key + 8;
if (version == PKCS5v2 || version == PKCS12)
desIv = cbcIv;
Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
Des_CbcDecrypt(&dec, input, input, length);
break;
}
case DES3_TYPE:
{
Des3 dec;
byte* desIv = key + 24;
if (version == PKCS5v2 || version == PKCS12)
desIv = cbcIv;
Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
Des3_CbcDecrypt(&dec, input, input, length);
break;
}
case RC4_TYPE:
{
Arc4 dec;
Arc4SetKey(&dec, key, derivedLen);
Arc4Process(&dec, input, input, length);
break;
}
default:
return -1; /* unknown algo id */
}
@@ -589,8 +697,10 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
{
word32 inOutIdx = 0, oid;
int type, algo, version, length, iterations, saltSz, id;
int type, first, second, length, iterations, saltSz, id;
int version;
byte salt[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
@@ -601,12 +711,27 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
version = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */
algo = input[inOutIdx - 1]; /* version.algo, algo id last byte */
first = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */
second = input[inOutIdx - 1]; /* version.algo, algo id last byte */
if (CheckAlgo(version, algo, &id) < 0)
if (CheckAlgo(first, second, &id, &version) < 0)
return ASN_INPUT_E; /* Algo ID error */
if (version == PKCS5v2) {
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
if ((word32)length > (sz - inOutIdx))
return ASN_INPUT_E;
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
if (oid != PBKDF2_OID)
return ASN_PARSE_E;
}
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
@@ -631,6 +756,27 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
if (GetShortInt(input, &inOutIdx, &iterations) < 0)
return ASN_PARSE_E;
if (version == PKCS5v2) {
/* get encryption algo */
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
if (CheckAlgoV2(oid, &id) < 0)
return ASN_PARSE_E; /* PKCS v2 algo id error */
if (input[inOutIdx++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
if (GetLength(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
if ((word32)length > (sz - inOutIdx))
return ASN_INPUT_E;
XMEMCPY(cbcIv, &input[inOutIdx], length);
inOutIdx += length;
}
if (input[inOutIdx++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
@@ -641,7 +787,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
return ASN_INPUT_E;
if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length) < 0)
input + inOutIdx, length, version, cbcIv) < 0)
return ASN_INPUT_E; /* decrypt failure */
XMEMMOVE(input, input + inOutIdx, length);

View File

@@ -3591,7 +3591,7 @@ int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
}
#if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC)
#if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_PWDBASED)
/* c = a * a (mod b) */
int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)

View File

@@ -24,6 +24,7 @@
#include "pwdbased.h"
#include "ctc_hmac.h"
#include "integer.h"
#ifdef CYASSL_SHA512
#include "sha512.h"
#endif
@@ -148,5 +149,159 @@ int PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt,
return 0;
}
int PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt,
int saltLen, int iterations, int kLen, int hashType, int id)
{
/* all in bytes instead of bits */
word32 u, v, dLen, pLen, iLen, sLen, totalLen;
int dynamic = 0;
int ret = 0;
int i;
byte *D, *S, *P, *I;
byte staticBuffer[1024];
byte* buffer = staticBuffer;
#ifdef CYASSL_SHA512
byte Ai[SHA512_DIGEST_SIZE];
byte B[SHA512_BLOCK_SIZE];
#else
byte Ai[SHA256_DIGEST_SIZE];
byte B[SHA256_BLOCK_SIZE];
#endif
if (!iterations)
iterations = 1;
if (hashType == MD5) {
v = MD5_BLOCK_SIZE;
u = MD5_DIGEST_SIZE;
}
else if (hashType == SHA) {
v = SHA_BLOCK_SIZE;
u = SHA_DIGEST_SIZE;
}
else if (hashType == SHA256) {
v = SHA256_BLOCK_SIZE;
u = SHA256_DIGEST_SIZE;
}
#ifdef CYASSL_SHA512
else if (hashType == SHA512) {
v = SHA512_BLOCK_SIZE;
u = SHA512_DIGEST_SIZE;
}
#endif
else
return -1; /* bad hashType */
dLen = v;
sLen = v * ((saltLen + v - 1) / v);
if (passLen)
pLen = v * ((passLen + v - 1) / v);
else
pLen = 0;
iLen = sLen + pLen;
totalLen = dLen + sLen + pLen;
if (totalLen > sizeof(staticBuffer)) {
buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY);
if (buffer == NULL) return -1;
dynamic = 1;
}
D = buffer;
S = D + dLen;
P = S + sLen;
I = S;
XMEMSET(D, id, dLen);
for (i = 0; i < sLen; i++)
S[i] = salt[i % saltLen];
for (i = 0; i < pLen; i++)
P[i] = passwd[i % passLen];
while (kLen > 0) {
word32 currentLen;
mp_int B1;
if (hashType == MD5) {
}
else if (hashType == SHA) {
Sha sha;
InitSha(&sha);
ShaUpdate(&sha, buffer, totalLen);
ShaFinal(&sha, Ai);
for (i = 1; i < iterations; i++) {
ShaUpdate(&sha, Ai, u);
ShaFinal(&sha, Ai);
}
}
else if (hashType == SHA256) {
}
#ifdef CYASSL_SHA512
else if (hashType == SHA512) {
}
#endif
for (i = 0; i < v; i++)
B[i] = Ai[i % u];
mp_init(&B1);
if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY)
ret = -1;
else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY) {
ret = -1;
mp_clear(&B1);
break;
}
for (i = 0; i < iLen; i += v) {
int outSz;
mp_int i1;
mp_int res;
mp_init(&i1);
mp_init(&res);
if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY)
ret = -1;
else if (mp_add(&i1, &B1, &res) != MP_OKAY)
ret = -1;
else if ( (outSz = mp_unsigned_bin_size(&res)) < 0)
ret = -1;
else {
if (outSz > v) {
/* take off MSB */
byte tmp[129];
mp_to_unsigned_bin(&res, tmp);
XMEMCPY(I + i, tmp + 1, v);
}
else if (outSz < v) {
XMEMSET(I + i, 0, v - outSz);
mp_to_unsigned_bin(&res, I + i + v - outSz);
}
else
mp_to_unsigned_bin(&res, I + i);
}
mp_clear(&i1);
mp_clear(&res);
if (ret < 0) break;
}
currentLen = min(kLen, u);
XMEMCPY(output, Ai, currentLen);
output += currentLen;
kLen -= currentLen;
mp_clear(&B1);
}
if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY);
return ret;
}
#endif /* NO_PWDBASED */

View File

@@ -2302,11 +2302,7 @@ void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
#endif /* CYASSL_KEY_GEN */
#ifdef HAVE_ECC
/* chars used in radix conversions */
const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
#if defined(HAVE_ECC) || !defined(NO_PWDBASED)
/* c = a + b */
void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
@@ -2315,6 +2311,20 @@ void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
fp_add(a,&tmp,c);
}
/* external compatibility */
int mp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
fp_add_d(a, b, c);
return MP_OKAY;
}
#endif /* HAVE_ECC || !NO_PWDBASED */
#ifdef HAVE_ECC
/* chars used in radix conversions */
const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
int fp_read_radix(fp_int *a, const char *str, int radix)
{

View File

@@ -1647,6 +1647,48 @@ int openssl_test()
#ifndef NO_PWDBASED
int pkcs12_test()
{
const byte passwd[] = { 0x00, 0x73, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x67,
0x00, 0x00 };
const byte salt[] = { 0x0a, 0x58, 0xCF, 0x64, 0x53, 0x0d, 0x82, 0x3f };
const byte passwd2[] = { 0x00, 0x71, 0x00, 0x75, 0x00, 0x65, 0x00, 0x65,
0x00, 0x67, 0x00, 0x00 };
const byte salt2[] = { 0x16, 0x82, 0xC0, 0xfC, 0x5b, 0x3f, 0x7e, 0xc5 };
byte derived[64];
const byte verify[] = {
0x8A, 0xAA, 0xE6, 0x29, 0x7B, 0x6C, 0xB0, 0x46,
0x42, 0xAB, 0x5B, 0x07, 0x78, 0x51, 0x28, 0x4E,
0xB7, 0x12, 0x8F, 0x1A, 0x2A, 0x7F, 0xBC, 0xA3
};
const byte verify2[] = {
0x48, 0x3D, 0xD6, 0xE9, 0x19, 0xD7, 0xDE, 0x2E,
0x8E, 0x64, 0x8B, 0xA8, 0xF8, 0x62, 0xF3, 0xFB,
0xFB, 0xDC, 0x2B, 0xCB, 0x2C, 0x02, 0x95, 0x7F
};
int id = 1;
int kLen = 24;
int iterations = 1;
int ret = PKCS12_PBKDF(derived, passwd, sizeof(passwd), salt, 8, iterations,
kLen, SHA, id);
if ( (ret = memcmp(derived, verify, kLen)) != 0)
return -103;
iterations = 1000;
ret = PKCS12_PBKDF(derived, passwd2, sizeof(passwd2), salt2, 8, iterations,
kLen, SHA, id);
if ( (ret = memcmp(derived, verify2, 24)) != 0)
return -104;
return 0;
}
int pbkdf2_test()
{
char passwd[] = "password";
@@ -1665,7 +1707,7 @@ int pbkdf2_test()
SHA);
if (memcmp(derived, verify, sizeof(verify)) != 0)
return -101;
return -102;
return 0;
}
@@ -1697,7 +1739,9 @@ int pbkdf1_test()
int pwdbased_test()
{
int ret = pbkdf1_test();
return ret + pbkdf2_test();
ret += pbkdf2_test();
return ret + pkcs12_test();
}
#endif /* NO_PWDBASED */

View File

@@ -182,11 +182,16 @@ static INLINE void showPeer(SSL* ssl)
subject);
ret = CyaSSL_X509_get_serial_number(peer, serial, &sz);
if (ret == 0) {
int i;
printf(" serial number");
int i;
int strLen;
char serialMsg[80];
/* testsuite has multiple threads writing to stdout, get output
message ready to write once */
strLen = snprintf(serialMsg, 16, " serial number");
for (i = 0; i < sz; i++)
printf(":%02x", serial[i]);
printf("\n");
snprintf(serialMsg + strLen + (i*3), 4, ":%02x ", serial[i]);
printf("%s\n", serialMsg);
}
XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);

View File

@@ -1348,7 +1348,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list)
#endif
#ifndef NO_PSK
havePSK = ssl->optoins.havePSK;
havePSK = ssl->options.havePSK;
#endif
if (ssl->options.side != SERVER_END) {