--- pgp/rsaref/source/r_enhanc.c 2018/04/24 16:40:41 1.1 +++ pgp/rsaref/source/r_enhanc.c 2018/04/24 16:41:46 1.1.1.2 @@ -1,965 +1,516 @@ -/* R_ENHANC.C - cryptographic enhancements for RSAREF - */ - -/* Copyright (C) RSA Laboratories, a division of RSA Data Security, - Inc., created 1991. All rights reserved. - */ - -#include "global.h" -#include "rsaref.h" -#include "r_random.h" -#include "rsa.h" - -/* DigestInfo encoding is DIGEST_INFO_A, then 2 or 5 (for MD2/MD5), - then DIGEST_INFO_B, then 16-byte message digest. - */ - -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 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) - -static unsigned char *PADDING[] = { - (unsigned char *)"", (unsigned char *)"\001", (unsigned char *)"\002\002", - (unsigned char *)"\003\003\003", (unsigned char *)"\004\004\004\004", - (unsigned char *)"\005\005\005\005\005", - (unsigned char *)"\006\006\006\006\006\006", - (unsigned char *)"\007\007\007\007\007\007\007", - (unsigned char *)"\010\010\010\010\010\010\010\010" -}; - -#define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN - -static void R_EncodeDigestInfo PROTO_LIST - ((unsigned char *, int, unsigned char *)); -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, - content, contentLen, recode, digestAlgorithm, privateKey) -unsigned char *encodedContent; /* encoded content */ -unsigned int *encodedContentLen; /* length of encoded content */ -unsigned char *encodedSignature; /* encoded signature */ -unsigned int *encodedSignatureLen; /* length of encoded signature */ -unsigned char *content; /* content */ -unsigned int contentLen; /* length of content */ -int recode; /* recoding flag */ -int digestAlgorithm; /* message-digest algorithm */ -R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ -{ - int status; - unsigned char signature[MAX_SIGNATURE_LEN]; - unsigned int signatureLen; - - if ((status = R_SignBlock - (signature, &signatureLen, content, contentLen, digestAlgorithm, - privateKey)) != 0) - return (status); - - R_EncodePEMBlock - (encodedSignature, encodedSignatureLen, signature, signatureLen); - - if (recode) - R_EncodePEMBlock - (encodedContent, encodedContentLen, content, contentLen); - - 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) -unsigned char *content; /* content */ -unsigned int *contentLen; /* length of content */ -unsigned char *encodedContent; /* (possibly) encoded content */ -unsigned int encodedContentLen; /* length of encoded content */ -unsigned char *encodedSignature; /* encoded signature */ -unsigned int encodedSignatureLen; /* length of encoded signature */ -int recode; /* recoding flag */ -int digestAlgorithm; /* message-digest algorithm */ -R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ -{ - unsigned char signature[MAX_SIGNATURE_LEN]; - unsigned int signatureLen; - - if (encodedSignatureLen > MAX_PEM_SIGNATURE_LEN) - return (RE_SIGNATURE_ENCODING); - - if (recode) { - if (R_DecodePEMBlock - (content, contentLen, encodedContent, encodedContentLen)) - return (RE_CONTENT_ENCODING); - } - else { - content = encodedContent; - *contentLen = encodedContentLen; - } - - if (R_DecodePEMBlock - (signature, &signatureLen, encodedSignature, encodedSignatureLen)) - return (RE_SIGNATURE_ENCODING); - - return (R_VerifyBlockSignature - (content, *contentLen, signature, signatureLen, digestAlgorithm, - publicKey)); -} - -int R_VerifyBlockSignature - (block, blockLen, signature, signatureLen, digestAlgorithm, publicKey) -unsigned char *block; /* block */ -unsigned int blockLen; /* length of block */ -unsigned char *signature; /* signature */ -unsigned int signatureLen; /* length of signature */ -int digestAlgorithm; /* message-digest algorithm */ -R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ -{ - R_SIGNATURE_CTX context; - int status; - - do { - if ((status = R_VerifyInit (&context, digestAlgorithm)) != 0) - break; - if ((status = R_VerifyUpdate (&context, block, blockLen)) != 0) - break; - if ((status = R_VerifyFinal (&context, signature, signatureLen, publicKey)) - != 0) - break; - } while (0); - - /* Zeroize sensitive information. */ - R_memset ((POINTER)&context, 0, sizeof (context)); - - return (status); -} - -int R_SealPEMBlock - (encryptedContent, encryptedContentLen, encryptedKey, encryptedKeyLen, - encryptedSignature, encryptedSignatureLen, iv, content, contentLen, - digestAlgorithm, publicKey, privateKey, randomStruct) -unsigned char *encryptedContent; /* encoded, encrypted content */ -unsigned int *encryptedContentLen; /* length */ -unsigned char *encryptedKey; /* encoded, encrypted key */ -unsigned int *encryptedKeyLen; /* length */ -unsigned char *encryptedSignature; /* encoded, encrypted signature */ -unsigned int *encryptedSignatureLen; /* length */ -unsigned char iv[8]; /* DES initialization vector */ -unsigned char *content; /* content */ -unsigned int contentLen; /* length of content */ -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], - signature[MAX_SIGNATURE_LEN], *encryptedKeys[1]; - unsigned int signatureLen, encryptedKeyBlockLen; - - do { - if ((status = R_SignBlock - (signature, &signatureLen, content, contentLen, digestAlgorithm, - privateKey)) != 0) - break; - - 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); - - EncryptPEMUpdateFinal - (&context, encryptedContent, encryptedContentLen, content, - contentLen); - - EncryptPEMUpdateFinal - (&context, encryptedSignature, encryptedSignatureLen, signature, - signatureLen); - } while (0); - - /* Zeroize sensitive information. - */ - R_memset ((POINTER)&context, 0, sizeof (context)); - R_memset ((POINTER)signature, 0, sizeof (signature)); - - return (status); -} - -int R_OpenPEMBlock - (content, contentLen, encryptedContent, encryptedContentLen, encryptedKey, - encryptedKeyLen, encryptedSignature, encryptedSignatureLen, - iv, digestAlgorithm, privateKey, publicKey) -unsigned char *content; /* content */ -unsigned int *contentLen; /* length of content */ -unsigned char *encryptedContent; /* encoded, encrypted content */ -unsigned int encryptedContentLen; /* length */ -unsigned char *encryptedKey; /* encoded, encrypted key */ -unsigned int encryptedKeyLen; /* length */ -unsigned char *encryptedSignature; /* encoded, encrypted signature */ -unsigned int encryptedSignatureLen; /* length */ -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], - signature[MAX_SIGNATURE_LEN]; - unsigned int encryptedKeyBlockLen, signatureLen; - - if (encryptedKeyLen > MAX_PEM_ENCRYPTED_KEY_LEN) - return (RE_KEY_ENCODING); - - if (encryptedSignatureLen > MAX_PEM_ENCRYPTED_SIGNATURE_LEN) - return (RE_SIGNATURE_ENCODING); - - do { - if (R_DecodePEMBlock - (encryptedKeyBlock, &encryptedKeyBlockLen, encryptedKey, - encryptedKeyLen) != 0) { - status = RE_KEY_ENCODING; - break; - } - - if ((status = R_OpenInit - (&context, EA_DES_CBC, encryptedKeyBlock, encryptedKeyBlockLen, - iv, privateKey)) != 0) - break; - - if ((status = DecryptPEMUpdateFinal - (&context, content, contentLen, encryptedContent, - encryptedContentLen)) != 0) { - if ((status == RE_LEN || status == RE_ENCODING)) - status = RE_CONTENT_ENCODING; - else - status = RE_KEY; - break; - } - - 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)) != 0) - break; - } while (0); - - /* Zeroize sensitive information. - */ - R_memset ((POINTER)&context, 0, sizeof (context)); - R_memset ((POINTER)signature, 0, sizeof (signature)); - - 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 */ -{ - R_DIGEST_CTX context; - int status; - - do { - if ((status = R_DigestInit (&context, digestAlgorithm)) != 0) - break; - if ((status = R_DigestUpdate (&context, block, blockLen)) != 0) - break; - if ((status = R_DigestFinal (&context, digest, digestLen)) != 0) - break; - } while (0); - - /* Zeroize sensitive information. */ - R_memset ((POINTER)&context, 0, sizeof (context)); - - return (status); -} - -/* Assumes digestAlgorithm is DA_MD2 or DA_MD5 and digest length is 16. - */ -static void R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest) -unsigned char *digestInfo; /* DigestInfo encoding */ -int digestAlgorithm; /* message-digest algorithm */ -unsigned char *digest; /* message digest */ -{ - R_memcpy - ((POINTER)digestInfo, (POINTER)DIGEST_INFO_A, DIGEST_INFO_A_LEN); - - digestInfo[DIGEST_INFO_A_LEN] = - (digestAlgorithm == DA_MD2) ? (unsigned char)2 : (unsigned char)5; - - R_memcpy - ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1], (POINTER)DIGEST_INFO_B, - DIGEST_INFO_B_LEN); - - R_memcpy - ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN], - (POINTER)digest, 16); -} - -/* 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 */ -{ - 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); - - /* len is always 32 */ - R_EncodePEMBlock (&output[32*i], &tempLen, encryptedPart, 24); - } - - /* 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; - - /* Zeroize sensitive information. - */ - R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart)); -} - -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 */ -{ - int status; - unsigned char encryptedPart[24]; - unsigned int i, len; - - do { - /* 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, &input[32*i], 32)) != 0) - break; - - /* Excpect no error return */ - R_OpenUpdate (context, output, &len, encryptedPart, 24); - output += len; - *outputLen += len; - } - if (status) - break; - - /* Decode the last part */ - if ((status = R_DecodePEMBlock - (encryptedPart, &len, &input[32*i], inputLen - 32*i)) != 0) - break; - - /* Decrypt the last part. - */ - R_OpenUpdate (context, output, &len, encryptedPart, len); - output += len; - *outputLen += len; - if ((status = R_OpenFinal (context, output, &len)) != 0) - break; - *outputLen += len; - } while (0); - - /* Zeroize sensitive information. - */ - 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); -} +/* R_ENHANC.C - cryptographic enhancements for RSAREF + */ + +/* Copyright (C) 1991-2 RSA Laboratories, a division of RSA Data + Security, Inc. 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[] = { + 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 }; +#define DIGEST_INFO_B_LEN sizeof (DIGEST_INFO_B) + +#define DIGEST_INFO_LEN (DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN + 16) + +static unsigned char *PADDING[] = { + (unsigned char *)"", (unsigned char *)"\001", (unsigned char *)"\002\002", + (unsigned char *)"\003\003\003", (unsigned char *)"\004\004\004\004", + (unsigned char *)"\005\005\005\005\005", + (unsigned char *)"\006\006\006\006\006\006", + (unsigned char *)"\007\007\007\007\007\007\007", + (unsigned char *)"\010\010\010\010\010\010\010\010" +}; + +#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])); + +int R_SignPEMBlock + (encodedContent, encodedContentLen, encodedSignature, encodedSignatureLen, + content, contentLen, recode, digestAlgorithm, privateKey) +unsigned char *encodedContent; /* encoded content */ +unsigned int *encodedContentLen; /* length of encoded content */ +unsigned char *encodedSignature; /* encoded signature */ +unsigned int *encodedSignatureLen; /* length of encoded signature */ +unsigned char *content; /* content */ +unsigned int contentLen; /* length of content */ +int recode; /* recoding flag */ +int digestAlgorithm; /* message-digest algorithm */ +R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ +{ + int status; + unsigned char signature[MAX_SIGNATURE_LEN]; + unsigned int signatureLen; + + if (status = R_SignBlock + (signature, &signatureLen, content, contentLen, digestAlgorithm, + privateKey)) + return (status); + + R_EncodePEMBlock + (encodedSignature, encodedSignatureLen, signature, signatureLen); + + if (recode) + R_EncodePEMBlock + (encodedContent, encodedContentLen, content, contentLen); + + return (0); +} + +int R_VerifyPEMSignature + (content, contentLen, encodedContent, encodedContentLen, encodedSignature, + encodedSignatureLen, recode, digestAlgorithm, publicKey) +unsigned char *content; /* content */ +unsigned int *contentLen; /* length of content */ +unsigned char *encodedContent; /* (possibly) encoded content */ +unsigned int encodedContentLen; /* length of encoded content */ +unsigned char *encodedSignature; /* encoded signature */ +unsigned int encodedSignatureLen; /* length of encoded signature */ +int recode; /* recoding flag */ +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; + + if (encodedSignatureLen > MAX_PEM_SIGNATURE_LEN) + return (RE_SIGNATURE_ENCODING); + + if (recode) { + if (status = R_DecodePEMBlock + (content, contentLen, encodedContent, encodedContentLen)) + return (RE_CONTENT_ENCODING); + } + else { + content = encodedContent; + *contentLen = encodedContentLen; + } + + if (status = R_DecodePEMBlock + (signature, &signatureLen, encodedSignature, encodedSignatureLen)) + return (RE_SIGNATURE_ENCODING); + + return (R_VerifyBlockSignature + (content, *contentLen, signature, signatureLen, digestAlgorithm, + publicKey)); +} + +int R_VerifyBlockSignature + (block, blockLen, signature, signatureLen, digestAlgorithm, publicKey) +unsigned char *block; /* block */ +unsigned int blockLen; /* length of block */ +unsigned char *signature; /* signature */ +unsigned int signatureLen; /* length of signature */ +int digestAlgorithm; /* message-digest algorithm */ +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 digestLen, originalDigestInfoLen; + + if (signatureLen > MAX_SIGNATURE_LEN) + return (RE_SIGNATURE); + + do { + if (status = R_DigestBlock + (digest, &digestLen, block, blockLen, digestAlgorithm)) + break; + + R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest); + + if (status = RSAPublicDecrypt + (originalDigestInfo, &originalDigestInfoLen, signature, signatureLen, + publicKey)) { + status = RE_PUBLIC_KEY; + break; + } + + if ((originalDigestInfoLen != DIGEST_INFO_LEN) || + (R_memcmp + ((POINTER)originalDigestInfo, (POINTER)digestInfo, + DIGEST_INFO_LEN))) { + status = RE_SIGNATURE; + 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)); + + return (status); +} + +int R_SealPEMBlock + (encryptedContent, encryptedContentLen, encryptedKey, encryptedKeyLen, + encryptedSignature, encryptedSignatureLen, iv, content, contentLen, + digestAlgorithm, publicKey, privateKey, randomStruct) +unsigned char *encryptedContent; /* encoded, encrypted content */ +unsigned int *encryptedContentLen; /* length */ +unsigned char *encryptedKey; /* encoded, encrypted key */ +unsigned int *encryptedKeyLen; /* length */ +unsigned char *encryptedSignature; /* encoded, encrypted signature */ +unsigned int *encryptedSignatureLen; /* length */ +unsigned char iv[8]; /* DES initializing vector */ +unsigned char *content; /* content */ +unsigned int contentLen; /* length of content */ +int digestAlgorithm; /* message-digest algorithm */ +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 */ +{ + int status; + unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], key[8], + signature[MAX_SIGNATURE_LEN]; + unsigned int encryptedKeyBlockLen, signatureLen; + + 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))) + break; + + R_EncryptPEMBlock + (encryptedContent, encryptedContentLen, content, contentLen, key, iv); + + if (status = RSAPublicEncrypt + (encryptedKeyBlock, &encryptedKeyBlockLen, key, 8, publicKey, + randomStruct)) { + status = RE_PUBLIC_KEY; + break; + } + + R_EncodePEMBlock + (encryptedKey, encryptedKeyLen, encryptedKeyBlock, + encryptedKeyBlockLen); + + R_EncryptPEMBlock + (encryptedSignature, encryptedSignatureLen, signature, signatureLen, + key, iv); + + } while (0); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)key, 0, sizeof (key)); + R_memset ((POINTER)signature, 0, sizeof (signature)); + + return (status); +} + +int R_OpenPEMBlock + (content, contentLen, encryptedContent, encryptedContentLen, encryptedKey, + encryptedKeyLen, encryptedSignature, encryptedSignatureLen, + iv, digestAlgorithm, privateKey, publicKey) +unsigned char *content; /* content */ +unsigned int *contentLen; /* length of content */ +unsigned char *encryptedContent; /* encoded, encrypted content */ +unsigned int encryptedContentLen; /* length */ +unsigned char *encryptedKey; /* encoded, encrypted key */ +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 */ +R_RSA_PRIVATE_KEY *privateKey; /* recipient's RSA private key */ +R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ +{ + int status; + unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], + key[MAX_ENCRYPTED_KEY_LEN], signature[MAX_SIGNATURE_LEN]; + unsigned int encryptedKeyBlockLen, keyLen, signatureLen; + + if (encryptedKeyLen > MAX_PEM_ENCRYPTED_KEY_LEN) + return (RE_KEY_ENCODING); + + if (encryptedSignatureLen > MAX_PEM_ENCRYPTED_SIGNATURE_LEN) + return (RE_SIGNATURE_ENCODING); + + do { + if (status = R_DecodePEMBlock + (encryptedKeyBlock, &encryptedKeyBlockLen, encryptedKey, + encryptedKeyLen)) { + status = RE_KEY_ENCODING; + break; + } + + if (status = RSAPrivateDecrypt + (key, &keyLen, encryptedKeyBlock, encryptedKeyBlockLen, privateKey)) { + status = RE_PRIVATE_KEY; + break; + } + + if (keyLen != 8) { + status = RE_PRIVATE_KEY; + break; + } + + if (status = R_DecryptPEMBlock + (content, contentLen, encryptedContent, encryptedContentLen, key, + iv)) { + if ((status == RE_LEN || status == RE_ENCODING)) + status = RE_CONTENT_ENCODING; + else + status = RE_KEY; + break; + } + + if (status = R_DecryptPEMBlock + (signature, &signatureLen, encryptedSignature, encryptedSignatureLen, + key, iv)) { + if ((status == RE_LEN || status == RE_ENCODING)) + status = RE_SIGNATURE_ENCODING; + else + status = RE_KEY; + } + + if (status = R_VerifyBlockSignature + (content, *contentLen, signature, signatureLen, digestAlgorithm, + publicKey)) + break; + + } while (0); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)key, 0, sizeof (key)); + 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 */ +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 */ +{ + 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)) + break; + + R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest); + + if (status = RSAPrivateEncrypt + (signature, signatureLen, digestInfo, DIGEST_INFO_LEN, privateKey)) { + status = RE_PRIVATE_KEY; + 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; + + case DA_MD5: + MD5Init (&md5Context); + MD5Update (&md5Context, block, blockLen); + MD5Final (digest, &md5Context); + *digestLen = 16; + break; + + default: + status = RE_DIGEST_ALGORITHM; + } + + return (status); +} + +/* Assumes digestAlgorithm is DA_MD2 or DA_MD5 and digest length is 16. + */ +static void R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest) +unsigned char *digestInfo; /* DigestInfo encoding */ +int digestAlgorithm; /* message-digest algorithm */ +unsigned char *digest; /* message digest */ +{ + R_memcpy + ((POINTER)digestInfo, (POINTER)DIGEST_INFO_A, DIGEST_INFO_A_LEN); + + digestInfo[DIGEST_INFO_A_LEN] = + (digestAlgorithm == DA_MD2) ? (unsigned char)2 : (unsigned char)5; + + R_memcpy + ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1], (POINTER)DIGEST_INFO_B, + DIGEST_INFO_B_LEN); + + R_memcpy + ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN], + (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 */ +{ + DES_CBC_CTX context; + unsigned char encryptedPart[24], lastPart[24]; + unsigned int i, lastPartLen, len, padLen; + + DES_CBCInit (&context, key, iv, 1); + + 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); + } + + 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; + + DES_CBCFinal (&context); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); +} + +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 */ +{ + 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; + + do { + for (i = 0; i < (encryptedBlockLen-1)/32; i++) { + /* len is always 24 */ + if (status = R_DecodePEMBlock + (encryptedPart, &len, &encryptedBlock[32*i], 32)) + break; + DES_CBCUpdate (&context, &block[24*i], encryptedPart, 24); + } + if (status) + break; + + len = encryptedBlockLen - 32*i; + if (status = R_DecodePEMBlock + (encryptedPart, &lastPartLen, &encryptedBlock[32*i], len)) + break; + + if (lastPartLen % 8) { + status = RE_DATA; + 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; + break; + } + + R_memcpy ((POINTER)&block[24*i], (POINTER)lastPart, lastPartLen - padLen); + *blockLen = 24*i + lastPartLen - padLen; + + } while (0); + + DES_CBCFinal (&context); + + /* Zeroize sensitive information. + */ + R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); + + return (status); +}