📄 pgpmsrsaglue.c
字号:
/*
* pgpMSRSAGlue.c - Interface to Microsoft CryptoAPI for RSA support
*
* This is an alternative to pgpRSAGlue.c, and should be used if that
* module cannot be used for legal reasons. It is only usable on
* platforms which include Microsoft CAPI support.
*
* This code only accepts PKCS-style padding. Very old versions of PGP
* used a different padding style, which will not be compatible with
* this module.
*
* $Id: pgpMSRSAGlue.c,v 1.11 1999/04/07 23:06:10 cpeterson Exp $
*/
#include "pgpSDKBuildFlags.h"
/*
* This entire source file is under the control of the following conditional:
*/
#if PGP_USECAPIFORRSA /* [ */
#include "pgpConfig.h"
#include "pgpDebug.h"
#include "pgpPubKey.h"
#include "pgpRSAGlue.h"
#include "pgpKeyMisc.h"
#include "bn.h"
#include "pgpErrors.h"
#include "pgpRandomX9_17.h"
#include "pgpMem.h"
#include "pgpHashPriv.h"
#include "pgpMSRSAGlue.h"
/* Early versions of wincrypt.h are missing these */
#ifndef MS_ENH_PROV
#define MS_ENH_PROV_A "Microsoft Enhanced Cryptographic Provider v1.0"
#define MS_ENH_PROV_W L"Microsoft Enhanced Cryptographic Provider v1.0"
#ifdef UNICODE
#define MS_ENH_PROV MS_ENH_PROV_W
#else
#define MS_ENH_PROV MS_ENH_PROV_A
#endif
#endif /* MS_ENH_PROV */
#ifndef CALG_3DES
#define CALG_3DES 0x00006603
#endif /* CALG_3DES */
/* Shorthand for accessing CAPI externs */
#define ex pgp_CAPI_externs
/* Our key container name, chosen not to conflict with a user name */
#define PGPCONTAINER "PGPreservedContainer"
/* Magic values for blob headers */
#define RSAPUBMAGIC 0x31415352
#define RSAPRIVMAGIC 0x32415352
#define BVERSION 2
/* Byte packing macros, little endian */
#define B4(val) (val)&0xff, ((val)>>8)&0xff, ((val)>>16)&0xff, ((val)>>24)&0xff
#define B2(val) (val)&0xff, ((val)>>8)&0xff
/* Round n up to be a multiple of r */
#define MULOF(n,r) ((((n)+(r)-1)/(r))*(r))
/* Blob definitions */
/* Public key blob header */
typedef struct _PUBLICKEYBLOBHDR
{
BLOBHEADER header;
RSAPUBKEY rsapubkey;
} PUBLICKEYBLOBHDR;
/* Followed by modulus, rsapubkey.bitlen bits long, little endian */
/* Note that this is the same as PUBLICKEYBLOBHDR, just what follows differs */
typedef struct _PRIVATEKEYBLOBHDR
{
BLOBHEADER header;
RSAPUBKEY rsapubkey;
} PRIVATEKEYBLOBHDR;
/* Followed by (all in little endian form, bitlen rounded up to mul of 64):
* modulus, rsapubkey.bitlen bits long,
* prime1, rsapubkey.bitlen/2 bits long,
* prime2, rsapubkey.bitlen/2 bits long, (prime1 > prime2)
* exponent1, rsapubkey.bitlen/2 bits long (privateExponent % (prime1-1))
* exponent2, rsapubkey.bitlen/2 bits long (privateExponent % (prime2-1))
* coefficient, rsapubkey.bitlen/2 bits long (inverse of prime2 mod prime1)
* privateExponent, rsapubkey.bitlen bits long
*/
typedef struct _SIMPLEBLOBHDR
{
BLOBHEADER header;
ALG_ID algid; /* of pubkey which encrypts session key */
} SIMPLEBLOBHDR;
/* Followed by session key, encrypted in PKCS-1 format with a public key */
/* Cache loadability information */
static PGPBoolean sLoadabilityTested = FALSE;
static PGPUInt32 sCAPIuse = 0;
/* Cache library handles and entry point vectors */
static HINSTANCE hLibAdv;
static HINSTANCE hLibCry;
#if !PGP_USECAPIFORMD2
static
#endif
CAPIEntries pgp_CAPI_externs; /* May be used by MD2 CAPI code */
#define DUMMYBITS 384
/*
* Dummy key, 384 bits, with public exponent = private exponent = 1
* Used when we don't want CAPI to do anything with our data.
*/
static PGPByte dummyKeyBlob[] = {
/* Blob header */
PRIVATEKEYBLOB, BVERSION, 0, 0, B4(CALG_RSA_KEYX),
/* RSAPUBKEY values */
B4(RSAPRIVMAGIC), B4(DUMMYBITS), B4(1),
/* Modulus */
0xc9, 0xd7, 0x0e, 0x21, 0xbb, 0xe0, 0xb5, 0x7a,
0x09, 0x3f, 0x64, 0x2d, 0xd7, 0xd0, 0x5c, 0xd6,
0x3b, 0xb3, 0xed, 0x00, 0xe3, 0x2f, 0x53, 0xd9,
0x26, 0xee, 0x47, 0x2f, 0x3e, 0x40, 0x5f, 0xc0,
0xf3, 0xb4, 0x25, 0x55, 0xea, 0xcf, 0x0b, 0x8f,
0x08, 0x28, 0x1a, 0xdd, 0x3b, 0x2a, 0x49, 0x8c,
/* Prime1 */
0xe7, 0xc0, 0xd7, 0x29, 0x28, 0x71, 0xe3, 0xc4,
0x05, 0x8c, 0xee, 0x1b, 0x37, 0xf4, 0x81, 0xe6,
0x5e, 0xb8, 0x4d, 0x38, 0xd3, 0x56, 0x80, 0xfa,
/* Prime2 */
0xcf, 0x9b, 0x02, 0x98, 0x55, 0x23, 0x09, 0xc6,
0x44, 0x82, 0x69, 0x63, 0xae, 0x68, 0xe1, 0xd2,
0x25, 0xfc, 0xe6, 0xe6, 0xc4, 0x7b, 0x5d, 0x8f,
/* Exponent1 */
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Exponent2 */
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Coefficient */
0x12, 0x12, 0xcd, 0x7f, 0x49, 0x92, 0xdf, 0x92,
0x3e, 0x0c, 0xc6, 0x76, 0x8e, 0x6e, 0x72, 0xd7,
0xe6, 0x94, 0xdf, 0xd8, 0xc5, 0x7c, 0x7f, 0x1e,
/* Private exponent */
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* Returns TRUE if we were able to find everything and can use CAPI */
static PGPBoolean
LoadCAPIEntryPoints ()
{
PGPBoolean success = FALSE;
if (!(ex.CryptAcquireContext = GetProcAddress (hLibAdv,
"CryptAcquireContextA")) &&
!(ex.CryptAcquireContext = GetProcAddress (hLibCry,
"CryptAcquireContextA")))
goto done;
if (!(ex.CryptReleaseContext = GetProcAddress (hLibAdv,
"CryptReleaseContext")) &&
!(ex.CryptReleaseContext = GetProcAddress (hLibCry,
"CryptReleaseContext")))
goto done;
if (!(ex.CryptImportKey = GetProcAddress (hLibAdv,
"CryptImportKey")) &&
!(ex.CryptImportKey = GetProcAddress (hLibCry,
"CryptImportKey")))
goto done;
if (!(ex.CryptExportKey = GetProcAddress (hLibAdv,
"CryptExportKey")) &&
!(ex.CryptExportKey = GetProcAddress (hLibCry,
"CryptExportKey")))
goto done;
if (!(ex.CryptDestroyKey = GetProcAddress (hLibAdv,
"CryptDestroyKey")) &&
!(ex.CryptDestroyKey = GetProcAddress (hLibCry,
"CryptDestroyKey")))
goto done;
if (!(ex.CryptCreateHash = GetProcAddress (hLibAdv,
"CryptCreateHash")) &&
!(ex.CryptCreateHash = GetProcAddress (hLibCry,
"CryptCreateHash")))
goto done;
if (!(ex.CryptHashData = GetProcAddress (hLibAdv,
"CryptHashData")) &&
!(ex.CryptHashData = GetProcAddress (hLibCry,
"CryptHashData")))
goto done;
if (!(ex.CryptSetHashParam = GetProcAddress (hLibAdv,
"CryptSetHashParam")) &&
!(ex.CryptSetHashParam = GetProcAddress (hLibCry,
"CryptSetHashParam")))
goto done;
if (!(ex.CryptDestroyHash = GetProcAddress (hLibAdv,
"CryptDestroyHash")) &&
!(ex.CryptDestroyHash = GetProcAddress (hLibCry,
"CryptDestroyHash")))
goto done;
if (!(ex.CryptVerifySignature = GetProcAddress (hLibAdv,
"CryptVerifySignatureA")) &&
!(ex.CryptVerifySignature = GetProcAddress (hLibCry,
"CryptVerifySignatureA")))
goto done;
if (!(ex.CryptSignHash = GetProcAddress (hLibAdv,
"CryptSignHashA")) &&
!(ex.CryptSignHash = GetProcAddress (hLibCry,
"CryptSignHashA")))
goto done;
success = TRUE;
done:
if (!success) {
if (hLibAdv)
FreeLibrary (hLibAdv);
if (hLibCry)
FreeLibrary (hLibCry);
}
return success;
}
/* Test what CAPI features are available */
/* The compiler seems to be storing above the stack frame */
/* Try turning off optimizer */
#pragma optimize ("", off)
PGPUInt32
pgpCAPIuse ()
{
HCRYPTPROV hProv;
PGPBoolean DEFLoadable, ENHLoadable;
if (!sLoadabilityTested) {
sLoadabilityTested = TRUE;
sCAPIuse = 0;
hLibAdv = LoadLibrary ("advapi32.dll");
if (!hLibAdv)
return 0;
hLibCry = LoadLibrary ("crypt32.dll");
if (!LoadCAPIEntryPoints ())
return 0;
/* See if DEF provider is available */
DEFLoadable = ex.CryptAcquireContext (&hProv, NULL, MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (DEFLoadable)
ex.CryptReleaseContext (hProv);
ENHLoadable = ex.CryptAcquireContext (&hProv, NULL, MS_ENH_PROV,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (ENHLoadable)
ex.CryptReleaseContext (hProv);
sCAPIuse = (DEFLoadable ? PGP_PKUSE_SIGN : 0) |
(ENHLoadable ? PGP_PKUSE_ENCRYPT : 0);
}
return sCAPIuse;
}
/* Restore default optimizations */
#pragma optimize ("", on)
/*
* This returns nonzero if the key is too big, returning the
* maximum number of bits that the library can accept.
* We will also use it to check for constraints on how CAPI works.
* This may mean that we will return an error even when the key is
* smaller than the max.
*/
#define MAXSIZE 4096
int
rsaKeyTooBig(RSApub const *pub, RSAsec const *sec)
{
if (pub) {
if (bnBits(&pub->n) > MAXSIZE)
return MAXSIZE;
if (bnBytes(&pub->e) > sizeof(DWORD))
return MAXSIZE;
}
if (sec) {
if (bnBits(&sec->n) > MAXSIZE)
return MAXSIZE;
if (bnBytes(&sec->e) > sizeof(DWORD))
return MAXSIZE;
}
return 0; /* OK */
}
/* Tell the size needed for a PUBLICKEYBLOB from a RSApub */
static PGPSize
rpubk_size(RSApub const *pub)
{
PGPUInt32 bits = MULOF(bnBits(&pub->n), 64);
PGPUInt32 len = bits/8;
return sizeof(PUBLICKEYBLOBHDR) + len;
}
/* Tell the size needed for a PRIVATEKEYBLOB from a RSAsec */
static PGPSize
rprivk_size(RSAsec const *sec)
{
PGPUInt32 bits = MULOF(bnBits(&sec->n), 64);
PGPUInt32 len = bits/8;
return sizeof(PRIVATEKEYBLOBHDR) + (9*len)/2;
}
/* Tell the size needed for a SIMPLEKEYBLOB given encryption mod bits */
static PGPSize
rsesk_size(PGPUInt32 modbits)
{
modbits = MULOF(modbits, 8);
return sizeof(SIMPLEBLOBHDR) + modbits/8;
}
/* Initialize a PUBLICKEYBLOB pubkey structure from a RSApub. */
static void
rpubk_init(PUBLICKEYBLOBHDR *rpubk, RSApub const *pub)
{
PGPUInt32 bits = MULOF(bnBits(&pub->n), 64);
PGPUInt32 len = bits/8;
PGPByte *bnbuf;
pgpClearMemory(rpubk, sizeof (*rpubk) + len);
rpubk->header.bType = PUBLICKEYBLOB;
rpubk->header.bVersion = BVERSION;
rpubk->header.aiKeyAlg = CALG_RSA_KEYX;
rpubk->rsapubkey.magic = RSAPUBMAGIC;
rpubk->rsapubkey.bitlen = MULOF(bnBits(&pub->n), 8);
bnExtractLittleBytes(&pub->e, (PGPByte *)&rpubk->rsapubkey.pubexp, 0,
sizeof(rpubk->rsapubkey.pubexp));
bnbuf = (PGPByte *)rpubk + sizeof(*rpubk);
bnExtractLittleBytes(&pub->n, bnbuf, 0, len);
}
/* Initialize RSAREF privkey structure from a RSAsec. */
static void
rprivk_init(PRIVATEKEYBLOBHDR *rprivk, RSAsec const *sec,
PGPMemoryMgrRef mgr, PGPBoolean fSign)
{
PGPUInt32 bits = MULOF(bnBits(&sec->n), 64);
PGPUInt32 len = bits/8;
BigNum dmodp, dmodq, tmp;
PGPByte *bnbuf;
pgpClearMemory(rprivk, sizeof (*rprivk) + (9*len)/2);
/* Calculate d mod p-1 and d mod q-1 */
bnBegin(&dmodp, mgr, TRUE);
bnBegin(&dmodq, mgr, TRUE);
bnBegin(&tmp, mgr, TRUE);
bnCopy(&tmp, &sec->p);
bnSubQ(&tmp, 1);
bnMod(&dmodp, &sec->d, &tmp);
bnCopy(&tmp, &sec->q);
bnSubQ(&tmp, 1);
bnMod(&dmodq, &sec->d, &tmp);
/* Fill in structure */
rprivk->header.bType = PRIVATEKEYBLOB;
rprivk->header.bVersion = BVERSION;
rprivk->header.aiKeyAlg = fSign ? CALG_RSA_SIGN : CALG_RSA_KEYX;
rprivk->rsapubkey.magic = RSAPRIVMAGIC;
rprivk->rsapubkey.bitlen = MULOF(bnBits(&sec->n), 8);
bnExtractLittleBytes(&sec->e, (PGPByte *)&rprivk->rsapubkey.pubexp, 0,
sizeof(rprivk->rsapubkey.pubexp));
bnbuf = (PGPByte *)rprivk + sizeof(*rprivk);
bnExtractLittleBytes(&sec->n, bnbuf, 0, len);
bnbuf += len;
/* CAPI uses convention p > q, the opposite of ours */
bnExtractLittleBytes(&sec->q, bnbuf, 0, len/2);
bnbuf += len/2;
bnExtractLittleBytes(&sec->p, bnbuf, 0, len/2);
bnbuf += len/2;
bnExtractLittleBytes(&dmodq, bnbuf, 0, len/2);
bnbuf += len/2;
bnExtractLittleBytes(&dmodp, bnbuf, 0, len/2);
bnbuf += len/2;
bnExtractLittleBytes(&sec->u, bnbuf, 0, len/2);
bnbuf += len/2;
bnExtractLittleBytes(&sec->d, bnbuf, 0, len);
bnEnd(&dmodp);
bnEnd(&dmodq);
bnEnd(&tmp);
}
/*
* Initialize a SIMPLEBLOB structure from a buffer, where the blob
* will be decrypted with a public key of the specified size in bits
* Note that rsesk is sensitive and should be allocated securely.
*/
static void
rsesk_initfrom_buf(SIMPLEBLOBHDR *rsesk, PGPByte const *in, unsigned len,
PGPUInt32 modbits, PGPMemoryMgrRef mgr,
PGPRandomContext const *rc)
{
PGPUInt32 modlen;
PGPByte *bnbuf;
BigNum skbn;
modbits = MULOF(modbits, 8);
modlen = modbits / 8;
pgpClearMemory(rsesk, sizeof (*rsesk) + modlen);
rsesk->header.bType = SIMPLEBLOB;
rsesk->header.bVersion = BVERSION;
rsesk->header.aiKeyAlg = CALG_3DES;
rsesk->algid = CALG_RSA_KEYX;
bnbuf = (PGPByte *)rsesk + sizeof(*rsesk);
bnBegin (&skbn, mgr, TRUE);
pgpPKCSPack (&skbn, in, len, PKCS_PAD_ENCRYPTED, modlen, rc);
bnExtractLittleBytes (&skbn, bnbuf, 0, modlen);
bnEnd (&skbn);
}
/*
* Initialize a SIMPLEBLOB structure from a buffer, where the blob
* will be decrypted with a public key of the specified size in bits
*/
static void
rsesk_initfrom_bn(SIMPLEBLOBHDR *rsesk, BigNum *bn, PGPUInt32 modbits)
{
PGPUInt32 modlen;
PGPByte *bnbuf;
modbits = MULOF(modbits, 8);
modlen = modbits / 8;
pgpClearMemory(rsesk, sizeof (*rsesk) + modlen);
rsesk->header.bType = SIMPLEBLOB;
rsesk->header.bVersion = BVERSION;
rsesk->header.aiKeyAlg = CALG_3DES;
rsesk->algid = CALG_RSA_KEYX;
bnbuf = (PGPByte *)rsesk + sizeof(*rsesk);
bnExtractLittleBytes (bn, bnbuf, 0, modlen);
}
/*
* Encrypt a buffer holding a session key with an RSA public key
*/
int
rsaPublicEncrypt(BigNum *bn, PGPByte const *in, unsigned len,
RSApub const *pub, PGPRandomContext const *rc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -