/* 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 *encryptedKe