--- rsaref/source/r_enhanc.c 2018/04/24 16:37:52 1.1 +++ rsaref/source/r_enhanc.c 2018/04/24 16:38:19 1.1.1.2 @@ -1,30 +1,26 @@ /* R_ENHANC.C - cryptographic enhancements for RSAREF */ -/* Copyright (C) 1991-2 RSA Laboratories, a division of RSA Data - Security, Inc. All rights reserved. +/* Copyright (C) RSA Laboratories, a division of RSA Data Security, + Inc., created 1991. All rights reserved. */ #include "global.h" #include "rsaref.h" -#include "r_encode.h" #include "r_random.h" #include "rsa.h" -#include "md2.h" -#include "md5.h" -#include "des.h" /* DigestInfo encoding is DIGEST_INFO_A, then 2 or 5 (for MD2/MD5), then DIGEST_INFO_B, then 16-byte message digest. */ -static char DIGEST_INFO_A[] = { +static unsigned char DIGEST_INFO_A[] = { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02 }; #define DIGEST_INFO_A_LEN sizeof (DIGEST_INFO_A) -static char DIGEST_INFO_B[] = { 0x05, 0x00, 0x04, 0x10 }; +static unsigned char DIGEST_INFO_B[] = { 0x05, 0x00, 0x04, 0x10 }; #define DIGEST_INFO_B_LEN sizeof (DIGEST_INFO_B) #define DIGEST_INFO_LEN (DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN + 16) @@ -40,17 +36,479 @@ static unsigned char *PADDING[] = { #define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN -static int R_SignBlock PROTO_LIST - ((unsigned char *, unsigned int *, unsigned char *, unsigned int, int, - R_RSA_PRIVATE_KEY *)); static void R_EncodeDigestInfo PROTO_LIST ((unsigned char *, int, unsigned char *)); -static void R_EncryptPEMBlock PROTO_LIST - ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - unsigned char [8], unsigned char [8])); -static int R_DecryptPEMBlock PROTO_LIST - ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - unsigned char [8], unsigned char [8])); +static void EncryptPEMUpdateFinal PROTO_LIST + ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *, + unsigned int)); +static int DecryptPEMUpdateFinal PROTO_LIST + ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *, + unsigned int)); +static int CipherInit PROTO_LIST + ((R_ENVELOPE_CTX *, int, unsigned char *, unsigned char *, int)); +static void CipherUpdate PROTO_LIST + ((R_ENVELOPE_CTX *, unsigned char *, unsigned char *, unsigned int)); +static void CipherRestart PROTO_LIST ((R_ENVELOPE_CTX *)); + +int R_DigestInit (context, digestAlgorithm) +R_DIGEST_CTX *context; /* new context */ +int digestAlgorithm; /* message-digest algorithm */ +{ + context->digestAlgorithm = digestAlgorithm; + + switch (digestAlgorithm) { + case DA_MD2: + MD2Init (&context->context.md2); + break; + + case DA_MD5: + MD5Init (&context->context.md5); + break; + + default: + return (RE_DIGEST_ALGORITHM); + } + + return (0); +} + +int R_DigestUpdate (context, partIn, partInLen) +R_DIGEST_CTX *context; /* context */ +unsigned char *partIn; /* next data part */ +unsigned int partInLen; /* length of next data part */ +{ + if (context->digestAlgorithm == DA_MD2) + MD2Update (&context->context.md2, partIn, partInLen); + else + MD5Update (&context->context.md5, partIn, partInLen); + return (0); +} + +int R_DigestFinal (context, digest, digestLen) +R_DIGEST_CTX *context; /* context */ +unsigned char *digest; /* message digest */ +unsigned int *digestLen; /* length of message digest */ +{ + *digestLen = 16; + if (context->digestAlgorithm == DA_MD2) + MD2Final (digest, &context->context.md2); + else + MD5Final (digest, &context->context.md5); + + return (0); +} + +int R_SignInit (context, digestAlgorithm) +R_SIGNATURE_CTX *context; /* new context */ +int digestAlgorithm; /* message-digest algorithm */ +{ + return (R_DigestInit (&context->digestContext, digestAlgorithm)); +} + +int R_SignUpdate (context, partIn, partInLen) +R_SIGNATURE_CTX *context; /* context */ +unsigned char *partIn; /* next data part */ +unsigned int partInLen; /* length of next data part */ +{ + return (R_DigestUpdate (&context->digestContext, partIn, partInLen)); +} + +int R_SignFinal (context, signature, signatureLen, privateKey) +R_SIGNATURE_CTX *context; /* context */ +unsigned char *signature; /* signature */ +unsigned int *signatureLen; /* length of signature */ +R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ +{ + int status; + unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN]; + unsigned int digestLen; + + do { + if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen)) + != 0) + break; + + R_EncodeDigestInfo + (digestInfo, context->digestContext.digestAlgorithm, digest); + + if (RSAPrivateEncrypt + (signature, signatureLen, digestInfo, DIGEST_INFO_LEN, privateKey) + != 0) { + status = RE_PRIVATE_KEY; + break; + } + + /* Reset for another verification. Assume Init won't fail */ + R_DigestInit + (&context->digestContext, context->digestContext.digestAlgorithm); + } while (0); + + /* Zeroize potentially sensitive information. + */ + R_memset ((POINTER)digest, 0, sizeof (digest)); + R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); + + return (status); +} + +int R_VerifyInit (context, digestAlgorithm) +R_SIGNATURE_CTX *context; /* new context */ +int digestAlgorithm; /* message-digest algorithm */ +{ + return (R_DigestInit (&context->digestContext, digestAlgorithm)); +} + +int R_VerifyUpdate (context, partIn, partInLen) +R_SIGNATURE_CTX *context; /* context */ +unsigned char *partIn; /* next data part */ +unsigned int partInLen; /* length of next data part */ +{ + return (R_DigestUpdate (&context->digestContext, partIn, partInLen)); +} + +int R_VerifyFinal (context, signature, signatureLen, publicKey) +R_SIGNATURE_CTX *context; /* context */ +unsigned char *signature; /* signature */ +unsigned int signatureLen; /* length of signature */ +R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ +{ + int status; + unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN], + originalDigestInfo[MAX_SIGNATURE_LEN]; + unsigned int originalDigestInfoLen, digestLen; + + if (signatureLen > MAX_SIGNATURE_LEN) + return (RE_LEN); + + status = 0; + do { + if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen)) + != 0) + break; + + R_EncodeDigestInfo + (digestInfo, context->digestContext.digestAlgorithm, digest); + + if (RSAPublicDecrypt + (originalDigestInfo, &originalDigestInfoLen, signature, signatureLen, + publicKey) != 0) { + status = RE_PUBLIC_KEY; + break; + } + + if ((originalDigestInfoLen != DIGEST_INFO_LEN) || + (R_memcmp + ((POINTER)originalDigestInfo, (POINTER)digestInfo, + DIGEST_INFO_LEN))) { + status = RE_SIGNATURE; + break; + } + + /* Reset for another verification. Assume Init won't fail */ + R_DigestInit + (&context->digestContext, context->digestContext.digestAlgorithm); + } while (0); + + /* Zeroize potentially sensitive information. + */ + R_memset ((POINTER)digest, 0, sizeof (digest)); + R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); + R_memset ((POINTER)originalDigestInfo, 0, sizeof (originalDigestInfo)); + + return (status); +} + +/* Caller must ASCII recode the encrypted keys if desired. + */ +int R_SealInit + (context, encryptedKeys, encryptedKeyLens, iv, publicKeyCount, publicKeys, + encryptionAlgorithm, randomStruct) +R_ENVELOPE_CTX *context; /* new context */ +unsigned char **encryptedKeys; /* encrypted keys */ +unsigned int *encryptedKeyLens; /* lengths of encrypted keys */ +unsigned char iv[8]; /* initialization vector */ +unsigned int publicKeyCount; /* number of public keys */ +R_RSA_PUBLIC_KEY **publicKeys; /* public keys */ +int encryptionAlgorithm; /* data encryption algorithm */ +R_RANDOM_STRUCT *randomStruct; /* random structure */ +{ + int status; + unsigned char key[24]; + unsigned int keyLen, i; + + do { + context->encryptionAlgorithm = encryptionAlgorithm; + + keyLen = (encryptionAlgorithm == EA_DES_CBC) ? 8 : 24; + if ((status = R_GenerateBytes (key, keyLen, randomStruct)) != 0) + break; + if ((status = R_GenerateBytes (iv, 8, randomStruct)) != 0) + break; + + if (encryptionAlgorithm == EA_DES_EDE2_CBC) + /* Make both E keys the same */ + R_memcpy ((POINTER)(key + 16), (POINTER)key, 8); + + if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 1)) != 0) + break; + + for (i = 0; i < publicKeyCount; ++i) { + if (RSAPublicEncrypt + (encryptedKeys[i], &encryptedKeyLens[i], key, keyLen, + publicKeys[i], randomStruct)) { + status = RE_PUBLIC_KEY; + break; + } + } + if (status != 0) + break; + + context->bufferLen = 0; + } while (0); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)key, 0, sizeof (key)); + + return (status); +} + +/* Assume partOut buffer is at least partInLen + 7, since this may flush + buffered input. + */ +int R_SealUpdate (context, partOut, partOutLen, partIn, partInLen) +R_ENVELOPE_CTX *context; /* context */ +unsigned char *partOut; /* next encrypted data part */ +unsigned int *partOutLen; /* length of next encrypted data part */ +unsigned char *partIn; /* next data part */ +unsigned int partInLen; /* length of next data part */ +{ + unsigned int tempLen; + + tempLen = 8 - context->bufferLen; + if (partInLen < tempLen) { + /* Just accumulate into buffer. + */ + R_memcpy + ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, + partInLen); + context->bufferLen += partInLen; + *partOutLen = 0; + return (0); + } + + /* Fill the buffer and encrypt. + */ + R_memcpy + ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, + tempLen); + CipherUpdate (context, partOut, context->buffer, 8); + partIn += tempLen; + partInLen -= tempLen; + partOut += 8; + *partOutLen = 8; + + /* Encrypt as many 8-byte blocks as possible. + */ + tempLen = 8 * (partInLen / 8); + CipherUpdate (context, partOut, partIn, tempLen); + partIn += tempLen; + partInLen -= tempLen; + *partOutLen += tempLen; + + /* Length is now less than 8, so copy remainder to buffer. + */ + R_memcpy + ((POINTER)context->buffer, (POINTER)partIn, + context->bufferLen = partInLen); + + return (0); +} + +/* Assume partOut buffer is at least 8 bytes. + */ +int R_SealFinal (context, partOut, partOutLen) +R_ENVELOPE_CTX *context; /* context */ +unsigned char *partOut; /* last encrypted data part */ +unsigned int *partOutLen; /* length of last encrypted data part */ +{ + unsigned int padLen; + + /* Pad and encrypt final block. + */ + padLen = 8 - context->bufferLen; + R_memset + ((POINTER)(context->buffer + context->bufferLen), (int)padLen, padLen); + CipherUpdate (context, partOut, context->buffer, 8); + *partOutLen = 8; + + /* Restart the context. + */ + CipherRestart (context); + context->bufferLen = 0; + + return (0); +} + +/* Assume caller has already ASCII decoded the encryptedKey if necessary. + */ +int R_OpenInit + (context, encryptionAlgorithm, encryptedKey, encryptedKeyLen, iv, privateKey) +R_ENVELOPE_CTX *context; /* new context */ +int encryptionAlgorithm; /* data encryption algorithm */ +unsigned char *encryptedKey; /* encrypted data encryption key */ +unsigned int encryptedKeyLen; /* length of encrypted key */ +unsigned char iv[8]; /* initialization vector */ +R_RSA_PRIVATE_KEY *privateKey; /* recipient's RSA private key */ +{ + int status; + unsigned char key[MAX_ENCRYPTED_KEY_LEN]; + unsigned int keyLen; + + if (encryptedKeyLen > MAX_ENCRYPTED_KEY_LEN) + return (RE_LEN); + + do { + context->encryptionAlgorithm = encryptionAlgorithm; + + if (RSAPrivateDecrypt + (key, &keyLen, encryptedKey, encryptedKeyLen, privateKey)) { + status = RE_PRIVATE_KEY; + break; + } + + if (encryptionAlgorithm == EA_DES_CBC) { + if (keyLen != 8) { + status = RE_PRIVATE_KEY; + break; + } + } + else { + if (keyLen != 24) { + status = RE_PRIVATE_KEY; + break; + } + } + + if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 0)) != 0) + break; + + context->bufferLen = 0; + } while (0); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)key, 0, sizeof (key)); + + return (status); +} + +/* Assume partOut buffer is at least partInLen + 7, since this may flush + buffered input. Always leaves at least one byte in buffer. + */ +int R_OpenUpdate (context, partOut, partOutLen, partIn, partInLen) +R_ENVELOPE_CTX *context; /* context */ +unsigned char *partOut; /* next recovered data part */ +unsigned int *partOutLen; /* length of next recovered data part */ +unsigned char *partIn; /* next encrypted data part */ +unsigned int partInLen; /* length of next encrypted data part */ +{ + unsigned int tempLen; + + tempLen = 8 - context->bufferLen; + if (partInLen <= tempLen) { + /* Just accumulate into buffer. + */ + R_memcpy + ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, + partInLen); + context->bufferLen += partInLen; + *partOutLen = 0; + return (0); + } + + /* Fill the buffer and decrypt. We know that there will be more left + in partIn after decrypting the buffer. + */ + R_memcpy + ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, + tempLen); + CipherUpdate (context, partOut, context->buffer, 8); + partIn += tempLen; + partInLen -= tempLen; + partOut += 8; + *partOutLen = 8; + + /* Decrypt as many 8 byte blocks as possible, leaving at least one byte + in partIn. + */ + tempLen = 8 * ((partInLen - 1) / 8); + CipherUpdate (context, partOut, partIn, tempLen); + partIn += tempLen; + partInLen -= tempLen; + *partOutLen += tempLen; + + /* Length is between 1 and 8, so copy into buffer. + */ + R_memcpy + ((POINTER)context->buffer, (POINTER)partIn, + context->bufferLen = partInLen); + + return (0); +} + +/* Assume partOut buffer is at least 7 bytes. + */ +int R_OpenFinal (context, partOut, partOutLen) +R_ENVELOPE_CTX *context; /* context */ +unsigned char *partOut; /* last recovered data part */ +unsigned int *partOutLen; /* length of last recovered data part */ +{ + int status; + unsigned char lastPart[8]; + unsigned int padLen; + + status = 0; + do { + if (context->bufferLen == 0) + /* There was no input data to decrypt */ + *partOutLen = 0; + else { + if (context->bufferLen != 8) { + status = RE_KEY; + break; + } + + /* Decrypt and strip padding from final block which is in buffer. + */ + CipherUpdate (context, lastPart, context->buffer, 8); + + padLen = lastPart[7]; + if (padLen == 0 || padLen > 8) { + status = RE_KEY; + break; + } + if (R_memcmp + ((POINTER)&lastPart[8 - padLen], PADDING[padLen], padLen) != 0) { + status = RE_KEY; + break; + } + + R_memcpy ((POINTER)partOut, (POINTER)lastPart, *partOutLen = 8 - padLen); + } + + /* Restart the context. + */ + CipherRestart (context); + context->bufferLen = 0; + } while (0); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); + + return (status); +} int R_SignPEMBlock (encodedContent, encodedContentLen, encodedSignature, encodedSignatureLen, @@ -69,9 +527,9 @@ R_RSA_PRIVATE_KEY *privateKey; unsigned char signature[MAX_SIGNATURE_LEN]; unsigned int signatureLen; - if (status = R_SignBlock - (signature, &signatureLen, content, contentLen, digestAlgorithm, - privateKey)) + if ((status = R_SignBlock + (signature, &signatureLen, content, contentLen, digestAlgorithm, + privateKey)) != 0) return (status); R_EncodePEMBlock @@ -84,6 +542,34 @@ R_RSA_PRIVATE_KEY *privateKey; return (0); } +int R_SignBlock + (signature, signatureLen, block, blockLen, digestAlgorithm, privateKey) +unsigned char *signature; /* signature */ +unsigned int *signatureLen; /* length of signature */ +unsigned char *block; /* block */ +unsigned int blockLen; /* length of block */ +int digestAlgorithm; /* message-digest algorithm */ +R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ +{ + R_SIGNATURE_CTX context; + int status; + + do { + if ((status = R_SignInit (&context, digestAlgorithm)) != 0) + break; + if ((status = R_SignUpdate (&context, block, blockLen)) != 0) + break; + if ((status = R_SignFinal (&context, signature, signatureLen, privateKey)) + != 0) + break; + } while (0); + + /* Zeroize sensitive information. */ + R_memset ((POINTER)&context, 0, sizeof (context)); + + return (status); +} + int R_VerifyPEMSignature (content, contentLen, encodedContent, encodedContentLen, encodedSignature, encodedSignatureLen, recode, digestAlgorithm, publicKey) @@ -97,7 +583,6 @@ int recode; int digestAlgorithm; /* message-digest algorithm */ R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ { - int status; unsigned char signature[MAX_SIGNATURE_LEN]; unsigned int signatureLen; @@ -105,7 +590,7 @@ R_RSA_PUBLIC_KEY *publicKey; return (RE_SIGNATURE_ENCODING); if (recode) { - if (status = R_DecodePEMBlock + if (R_DecodePEMBlock (content, contentLen, encodedContent, encodedContentLen)) return (RE_CONTENT_ENCODING); } @@ -114,7 +599,7 @@ R_RSA_PUBLIC_KEY *publicKey; *contentLen = encodedContentLen; } - if (status = R_DecodePEMBlock + if (R_DecodePEMBlock (signature, &signatureLen, encodedSignature, encodedSignatureLen)) return (RE_SIGNATURE_ENCODING); @@ -132,43 +617,21 @@ unsigned int signatureLen; int digestAlgorithm; /* message-digest algorithm */ R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ { + R_SIGNATURE_CTX context; int status; - unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN], - originalDigestInfo[MAX_SIGNATURE_LEN]; - unsigned int digestLen, originalDigestInfoLen; - - if (signatureLen > MAX_SIGNATURE_LEN) - return (RE_SIGNATURE); - + do { - if (status = R_DigestBlock - (digest, &digestLen, block, blockLen, digestAlgorithm)) + if ((status = R_VerifyInit (&context, digestAlgorithm)) != 0) break; - - R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest); - - if (status = RSAPublicDecrypt - (originalDigestInfo, &originalDigestInfoLen, signature, signatureLen, - publicKey)) { - status = RE_PUBLIC_KEY; + if ((status = R_VerifyUpdate (&context, block, blockLen)) != 0) break; - } - - if ((originalDigestInfoLen != DIGEST_INFO_LEN) || - (R_memcmp - ((POINTER)originalDigestInfo, (POINTER)digestInfo, - DIGEST_INFO_LEN))) { - status = RE_SIGNATURE; + if ((status = R_VerifyFinal (&context, signature, signatureLen, publicKey)) + != 0) break; - } - } while (0); - - /* Zeroize potentially sensitive information. - */ - R_memset ((POINTER)digest, 0, sizeof (digest)); - R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); - R_memset ((POINTER)originalDigestInfo, 0, sizeof (originalDigestInfo)); + + /* Zeroize sensitive information. */ + R_memset ((POINTER)&context, 0, sizeof (context)); return (status); } @@ -183,52 +646,50 @@ unsigned char *encryptedKey; unsigned int *encryptedKeyLen; /* length */ unsigned char *encryptedSignature; /* encoded, encrypted signature */ unsigned int *encryptedSignatureLen; /* length */ -unsigned char iv[8]; /* DES initializing vector */ +unsigned char iv[8]; /* DES initialization vector */ unsigned char *content; /* content */ unsigned int contentLen; /* length of content */ -int digestAlgorithm; /* message-digest algorithm */ +int digestAlgorithm; /* message-digest algorithms */ R_RSA_PUBLIC_KEY *publicKey; /* recipient's RSA public key */ R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ R_RANDOM_STRUCT *randomStruct; /* random structure */ { + R_ENVELOPE_CTX context; + R_RSA_PUBLIC_KEY *publicKeys[1]; int status; - unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], key[8], - signature[MAX_SIGNATURE_LEN]; - unsigned int encryptedKeyBlockLen, signatureLen; + unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], + signature[MAX_SIGNATURE_LEN], *encryptedKeys[1]; + unsigned int signatureLen, encryptedKeyBlockLen; do { - if (status = R_SignBlock - (signature, &signatureLen, content, contentLen, digestAlgorithm, - privateKey)) - break; - - if ((status = R_GenerateBytes (key, 8, randomStruct)) || - (status = R_GenerateBytes (iv, 8, randomStruct))) + if ((status = R_SignBlock + (signature, &signatureLen, content, contentLen, digestAlgorithm, + privateKey)) != 0) break; - R_EncryptPEMBlock - (encryptedContent, encryptedContentLen, content, contentLen, key, iv); - - if (status = RSAPublicEncrypt - (encryptedKeyBlock, &encryptedKeyBlockLen, key, 8, publicKey, - randomStruct)) { - status = RE_PUBLIC_KEY; + publicKeys[0] = publicKey; + encryptedKeys[0] = encryptedKeyBlock; + if ((status = R_SealInit + (&context, encryptedKeys, &encryptedKeyBlockLen, iv, 1, publicKeys, + EA_DES_CBC, randomStruct)) != 0) break; - } - + R_EncodePEMBlock (encryptedKey, encryptedKeyLen, encryptedKeyBlock, encryptedKeyBlockLen); - R_EncryptPEMBlock - (encryptedSignature, encryptedSignatureLen, signature, signatureLen, - key, iv); - + EncryptPEMUpdateFinal + (&context, encryptedContent, encryptedContentLen, content, + contentLen); + + EncryptPEMUpdateFinal + (&context, encryptedSignature, encryptedSignatureLen, signature, + signatureLen); } while (0); /* Zeroize sensitive information. */ - R_memset ((POINTER)key, 0, sizeof (key)); + R_memset ((POINTER)&context, 0, sizeof (context)); R_memset ((POINTER)signature, 0, sizeof (signature)); return (status); @@ -246,15 +707,16 @@ unsigned char *encryptedKey; unsigned int encryptedKeyLen; /* length */ unsigned char *encryptedSignature; /* encoded, encrypted signature */ unsigned int encryptedSignatureLen; /* length */ -unsigned char iv[8]; /* DES initializing vector */ -int digestAlgorithm; /* message-digest algorithm */ +unsigned char iv[8]; /* DES initialization vector */ +int digestAlgorithm; /* message-digest algorithms */ R_RSA_PRIVATE_KEY *privateKey; /* recipient's RSA private key */ R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ { + R_ENVELOPE_CTX context; int status; unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], - key[MAX_ENCRYPTED_KEY_LEN], signature[MAX_SIGNATURE_LEN]; - unsigned int encryptedKeyBlockLen, keyLen, signatureLen; + signature[MAX_SIGNATURE_LEN]; + unsigned int encryptedKeyBlockLen, signatureLen; if (encryptedKeyLen > MAX_PEM_ENCRYPTED_KEY_LEN) return (RE_KEY_ENCODING); @@ -263,27 +725,21 @@ R_RSA_PUBLIC_KEY *publicKey; return (RE_SIGNATURE_ENCODING); do { - if (status = R_DecodePEMBlock + if (R_DecodePEMBlock (encryptedKeyBlock, &encryptedKeyBlockLen, encryptedKey, - encryptedKeyLen)) { + encryptedKeyLen) != 0) { status = RE_KEY_ENCODING; break; } - if (status = RSAPrivateDecrypt - (key, &keyLen, encryptedKeyBlock, encryptedKeyBlockLen, privateKey)) { - status = RE_PRIVATE_KEY; + if ((status = R_OpenInit + (&context, EA_DES_CBC, encryptedKeyBlock, encryptedKeyBlockLen, + iv, privateKey)) != 0) break; - } - - if (keyLen != 8) { - status = RE_PRIVATE_KEY; - break; - } - - if (status = R_DecryptPEMBlock - (content, contentLen, encryptedContent, encryptedContentLen, key, - iv)) { + + if ((status = DecryptPEMUpdateFinal + (&context, content, contentLen, encryptedContent, + encryptedContentLen)) != 0) { if ((status == RE_LEN || status == RE_ENCODING)) status = RE_CONTENT_ENCODING; else @@ -291,98 +747,52 @@ R_RSA_PUBLIC_KEY *publicKey; break; } - if (status = R_DecryptPEMBlock - (signature, &signatureLen, encryptedSignature, encryptedSignatureLen, - key, iv)) { + if (status = DecryptPEMUpdateFinal + (&context, signature, &signatureLen, encryptedSignature, + encryptedSignatureLen)) { if ((status == RE_LEN || status == RE_ENCODING)) status = RE_SIGNATURE_ENCODING; else status = RE_KEY; + break; } - if (status = R_VerifyBlockSignature - (content, *contentLen, signature, signatureLen, digestAlgorithm, - publicKey)) + if ((status = R_VerifyBlockSignature + (content, *contentLen, signature, signatureLen, digestAlgorithm, + publicKey)) != 0) break; - } while (0); /* Zeroize sensitive information. */ - R_memset ((POINTER)key, 0, sizeof (key)); + R_memset ((POINTER)&context, 0, sizeof (context)); R_memset ((POINTER)signature, 0, sizeof (signature)); return (status); } -static int R_SignBlock - (signature, signatureLen, block, blockLen, digestAlgorithm, privateKey) -unsigned char *signature; /* signature */ -unsigned int *signatureLen; /* length of signature */ +int R_DigestBlock (digest, digestLen, block, blockLen, digestAlgorithm) +unsigned char *digest; /* message digest */ +unsigned int *digestLen; /* length of message digest */ unsigned char *block; /* block */ unsigned int blockLen; /* length of block */ int digestAlgorithm; /* message-digest algorithm */ -R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ { + R_DIGEST_CTX context; int status; - unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN]; - unsigned int digestLen; do { - if (status = R_DigestBlock - (digest, &digestLen, block, blockLen, digestAlgorithm)) + if ((status = R_DigestInit (&context, digestAlgorithm)) != 0) break; - - R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest); - - if (status = RSAPrivateEncrypt - (signature, signatureLen, digestInfo, DIGEST_INFO_LEN, privateKey)) { - status = RE_PRIVATE_KEY; + if ((status = R_DigestUpdate (&context, block, blockLen)) != 0) + break; + if ((status = R_DigestFinal (&context, digest, digestLen)) != 0) break; - } - } while (0); - - /* Zeroize potentially sensitive information. - */ - R_memset ((POINTER)digest, 0, sizeof (digest)); - R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); - return (status); -} - -int R_DigestBlock (digest, digestLen, block, blockLen, digestAlgorithm) -unsigned char *digest; /* message digest */ -unsigned int *digestLen; /* length of message digest */ -unsigned char *block; /* block */ -unsigned int blockLen; /* length of block */ -int digestAlgorithm; /* message-digest algorithm */ -{ - MD2_CTX md2Context; - MD5_CTX md5Context; - int status; - - status = 0; - - switch (digestAlgorithm) { - case DA_MD2: - MD2Init (&md2Context); - MD2Update (&md2Context, block, blockLen); - MD2Final (digest, &md2Context); - *digestLen = 16; - break; + /* Zeroize sensitive information. */ + R_memset ((POINTER)&context, 0, sizeof (context)); - case DA_MD5: - MD5Init (&md5Context); - MD5Update (&md5Context, block, blockLen); - MD5Final (digest, &md5Context); - *digestLen = 16; - break; - - default: - status = RE_DIGEST_ALGORITHM; - } - return (status); } @@ -408,109 +818,148 @@ unsigned char *digest; (POINTER)digest, 16); } -static void R_EncryptPEMBlock - (encryptedBlock, encryptedBlockLen, block, blockLen, key, iv) -unsigned char *encryptedBlock; /* encrypted, encoded block */ -unsigned int *encryptedBlockLen; /* length */ -unsigned char *block; /* block */ -unsigned int blockLen; /* length of block */ -unsigned char key[8]; /* DES key */ -unsigned char iv[8]; /* DES initialization vector */ +/* Call SealUpdate and SealFinal on the input and ASCII recode. + */ +static void EncryptPEMUpdateFinal + (context, output, outputLen, input, inputLen) +R_ENVELOPE_CTX *context; +unsigned char *output; /* encrypted, encoded block */ +unsigned int *outputLen; /* length of output */ +unsigned char *input; /* block to encrypt */ +unsigned int inputLen; /* length */ { - DES_CBC_CTX context; - unsigned char encryptedPart[24], lastPart[24]; - unsigned int i, lastPartLen, len, padLen; - - DES_CBCInit (&context, key, iv, 1); + unsigned char encryptedPart[24]; + unsigned int i, lastPartLen, tempLen, len; + + /* Choose a buffer size of 24 bytes to hold the temporary encrypted output + which will be encoded. + Encrypt and encode as many 24-byte blocks as possible. + */ + for (i = 0; i < inputLen / 24; ++i) { + /* Assume part out length will equal part in length since it is + a multiple of 8. Also assume no error output. */ + R_SealUpdate (context, encryptedPart, &tempLen, &input[24*i], 24); - for (i = 0; i < blockLen/24; i++) { - DES_CBCUpdate (&context, encryptedPart, &block[24*i], 24); /* len is always 32 */ - R_EncodePEMBlock (&encryptedBlock[32*i], &len, encryptedPart, 24); + R_EncodePEMBlock (&output[32*i], &tempLen, encryptedPart, 24); } - padLen = 8 - (blockLen % 8); - lastPartLen = blockLen - 24*i + padLen; - R_memcpy ((POINTER)lastPart, (POINTER)&block[24*i], lastPartLen - padLen); - R_memcpy - ((POINTER)&lastPart[lastPartLen - padLen], PADDING[padLen], padLen); - DES_CBCUpdate (&context, encryptedPart, lastPart, lastPartLen); - R_EncodePEMBlock - (&encryptedBlock[32*i], &len, encryptedPart, lastPartLen); - *encryptedBlockLen = 32*i + len; + /* Encrypt the last part into encryptedPart. + */ + R_SealUpdate + (context, encryptedPart, &lastPartLen, &input[24*i], inputLen - 24*i); + R_SealFinal (context, encryptedPart + lastPartLen, &len); + lastPartLen += len; + + R_EncodePEMBlock (&output[32*i], &len, encryptedPart, lastPartLen); + *outputLen = 32*i + len; - DES_CBCFinal (&context); - /* Zeroize sensitive information. */ - R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); + R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart)); } -static int R_DecryptPEMBlock - (block, blockLen, encryptedBlock, encryptedBlockLen, key, iv) -unsigned char *block; /* block */ -unsigned int *blockLen; /* length of block */ -unsigned char *encryptedBlock; /* encrypted, encoded block */ -unsigned int encryptedBlockLen; /* length */ -unsigned char key[8]; /* DES key */ -unsigned char iv[8]; /* DES initialization vector */ +static int DecryptPEMUpdateFinal (context, output, outputLen, input, inputLen) +R_ENVELOPE_CTX *context; +unsigned char *output; /* decoded, decrypted block */ +unsigned int *outputLen; /* length of output */ +unsigned char *input; /* encrypted, encoded block */ +unsigned int inputLen; /* length */ { - DES_CBC_CTX context; int status; - unsigned char encryptedPart[24], lastPart[24]; - unsigned int i, lastPartLen, len, padLen; - - if (encryptedBlockLen < 1) - return (RE_LEN); - - DES_CBCInit (&context, key, iv, 0); - - status = 0; + unsigned char encryptedPart[24]; + unsigned int i, len; do { - for (i = 0; i < (encryptedBlockLen-1)/32; i++) { + /* Choose a buffer size of 24 bytes to hold the temporary decoded output + which will be decrypted. + Decode and decrypt as many 32-byte input blocks as possible. + */ + *outputLen = 0; + for (i = 0; i < inputLen/32; i++) { /* len is always 24 */ - if (status = R_DecodePEMBlock - (encryptedPart, &len, &encryptedBlock[32*i], 32)) + if ((status = R_DecodePEMBlock + (encryptedPart, &len, &input[32*i], 32)) != 0) break; - DES_CBCUpdate (&context, &block[24*i], encryptedPart, 24); + + /* Excpect no error return */ + R_OpenUpdate (context, output, &len, encryptedPart, 24); + output += len; + *outputLen += len; } if (status) break; - - len = encryptedBlockLen - 32*i; - if (status = R_DecodePEMBlock - (encryptedPart, &lastPartLen, &encryptedBlock[32*i], len)) - break; - if (lastPartLen % 8) { - status = RE_DATA; + /* Decode the last part */ + if ((status = R_DecodePEMBlock + (encryptedPart, &len, &input[32*i], inputLen - 32*i)) != 0) break; - } - - DES_CBCUpdate (&context, lastPart, encryptedPart, lastPartLen); - padLen = lastPart[lastPartLen - 1]; - if (padLen > 8) { - status = RE_DATA; - break; - } - if (R_memcmp - ((POINTER)&lastPart[lastPartLen - padLen], PADDING[padLen], padLen)) { - status = RE_DATA; + /* Decrypt the last part. + */ + R_OpenUpdate (context, output, &len, encryptedPart, len); + output += len; + *outputLen += len; + if ((status = R_OpenFinal (context, output, &len)) != 0) break; - } - - R_memcpy ((POINTER)&block[24*i], (POINTER)lastPart, lastPartLen - padLen); - *blockLen = 24*i + lastPartLen - padLen; - + *outputLen += len; } while (0); - DES_CBCFinal (&context); - /* Zeroize sensitive information. */ - R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); + R_memset ((POINTER)&context, 0, sizeof (context)); + R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart)); return (status); } + +static int CipherInit (context, encryptionAlgorithm, key, iv, encrypt) +R_ENVELOPE_CTX *context; +int encryptionAlgorithm; +unsigned char *key; /* DES key */ +unsigned char *iv; /* DES initialization vector */ +int encrypt; /* encrypt flag (1 = encrypt, 0 = decrypt) */ +{ + switch (encryptionAlgorithm) { + case EA_DES_CBC: + DES_CBCInit (&context->cipherContext.des, key, iv, encrypt); + return (0); + case EA_DESX_CBC: + DESX_CBCInit (&context->cipherContext.desx, key, iv, encrypt); + return (0); + case EA_DES_EDE2_CBC: + case EA_DES_EDE3_CBC: + DES3_CBCInit (&context->cipherContext.des3, key, iv, encrypt); + return (0); + + default: + return (RE_ENCRYPTION_ALGORITHM); + } +} + +/* Assume len is a multiple of 8. + */ +static void CipherUpdate (context, output, input, len) +R_ENVELOPE_CTX *context; +unsigned char *output; /* output block */ +unsigned char *input; /* input block */ +unsigned int len; /* length of input and output blocks */ +{ + if (context->encryptionAlgorithm == EA_DES_CBC) + DES_CBCUpdate (&context->cipherContext.des, output, input, len); + else if (context->encryptionAlgorithm == EA_DESX_CBC) + DESX_CBCUpdate (&context->cipherContext.desx, output, input, len); + else + DES3_CBCUpdate (&context->cipherContext.des3, output, input, len); +} + +static void CipherRestart (context) +R_ENVELOPE_CTX *context; +{ + if (context->encryptionAlgorithm == EA_DES_CBC) + DES_CBCRestart (&context->cipherContext.des); + else if (context->encryptionAlgorithm == EA_DESX_CBC) + DESX_CBCRestart (&context->cipherContext.desx); + else + DES3_CBCRestart (&context->cipherContext.des3); +}