/* 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); }