📄 pgpmsrsaglue.c
字号:
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hDummy = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hSession = 0;
PUBLICKEYBLOBHDR *rpubk = NULL;
SIMPLEBLOBHDR *rsesk = NULL;
PGPUInt32 rpubksize;
PGPUInt32 rsesksize;
PGPByte *rseskdata;
PGPMemoryMgrRef mgr = pub->n.mgr;
PGPError err = kPGPError_NoErr;
/* Set the return number to 0 to start */
(void)bnSetQ(bn, 0);
if (!(pgpCAPIuse() & PGP_PKUSE_ENCRYPT))
return kPGPError_PublicKeyUnimplemented;
/* Get handle to the enhanced PROV_RSA_FULL provider */
/* Use our reserved container name, always start with an empty one */
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if(!ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Initialize CAPI public key structure */
rpubksize = rpubk_size (pub);
rpubk = PGPNewData (mgr, rpubksize, 0);
if (IsNull (rpubk)) {
err = kPGPError_OutOfMemory;
goto error;
}
rpubk_init(rpubk, pub);
/* Create dummy key for importing session key */
if (!ex.CryptImportKey (hProv, (BYTE *)&dummyKeyBlob,
sizeof(dummyKeyBlob), 0, 0, &hDummy)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Initialize and import session key */
rsesksize = rsesk_size (DUMMYBITS);
rsesk = PGPNewSecureData (mgr, rsesksize, 0);
if (IsNull (rsesk)) {
err = kPGPError_OutOfMemory;
goto error;
}
rsesk_initfrom_buf (rsesk, in, len, DUMMYBITS, mgr, rc);
if (!ex.CryptImportKey (hProv, (BYTE *)rsesk, rsesksize, hDummy,
CRYPT_EXPORTABLE, &hSession)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
PGPFreeData (rsesk);
rsesk = NULL;
/* Export session key now encrypted with user's public key */
if (!ex.CryptImportKey (hProv, (BYTE *)rpubk, rpubksize, 0, 0, &hKey)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* CAPI ovewrites more data than it should with nonstandard key sizes */
rsesksize = sizeof(*rsesk) + MULOF(bnBytes(&pub->n), 8);
rsesk = (SIMPLEBLOBHDR *)PGPNewData (mgr, rsesksize, 0);
if (!rsesk) {
err = kPGPError_OutOfMemory;
goto error;
}
pgpAssert (sizeof(rsesksize) == sizeof(DWORD));
if (!ex.CryptExportKey (hSession, hKey, SIMPLEBLOB, 0, (BYTE *)rsesk,
&rsesksize)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
pgpAssert (rsesksize == sizeof(*rsesk) + bnBytes(&pub->n));
/* Return in PGP bn format */
rseskdata = (PGPByte *)rsesk + sizeof(*rsesk);
bnInsertLittleBytes(bn, rseskdata, 0, bnBytes(&pub->n));
error:
if (hSession)
ex.CryptDestroyKey (hSession);
if (hKey)
ex.CryptDestroyKey (hKey);
if (hDummy)
ex.CryptDestroyKey (hDummy);
ex.CryptReleaseContext(hProv, 0);
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if (rsesk) {
pgpClearMemory (rsesk, rsesksize);
PGPFreeData (rsesk);
}
if (rpubk) {
pgpClearMemory (rpubk, rpubksize);
PGPFreeData (rpubk);
}
return err;
}
/*
* Performs an RSA decryption. Returns a prefix of the unwrapped
* data in the given buf. Returns the length of the untruncated
* data, which may exceed "len". Returns <0 on error.
*/
int
rsaPrivateDecrypt(PGPByte *outbuf, unsigned len, BigNum *bn,
RSAsec const *sec)
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hDummy = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hSession = 0;
PRIVATEKEYBLOBHDR *rprivk = NULL;
SIMPLEBLOBHDR *rsesk = NULL;
PGPUInt32 rprivksize;
PGPUInt32 rsesksize;
PGPByte *rseskdata;
PGPMemoryMgrRef mgr = bn->mgr;
PGPError err = kPGPError_NoErr;
BigNum bnsk;
if (!(pgpCAPIuse() & PGP_PKUSE_ENCRYPT))
return kPGPError_PublicKeyUnimplemented;
/* CAPI has bugs with keys not mult of 64 bits */
if ((bnBytes(bn) % 8) != 0)
return kPGPError_CAPIUnsupportedKey;
/* Get handle to the enhanced PROV_RSA_FULL provider */
/* Use our reserved container name, always start with an empty one */
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if(!ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Initialize and import private key structure */
rprivksize = rprivk_size (sec);
rprivk = PGPNewSecureData (mgr, rprivksize, 0);
if (IsNull (rprivk)) {
err = kPGPError_OutOfMemory;
goto error;
}
rprivk_init(rprivk, sec, mgr, FALSE);
if (!ex.CryptImportKey (hProv, (BYTE *)rprivk, rprivksize, 0, 0, &hKey)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Create SIMPLEBLOB from encrypted session key in bn */
rsesksize = rsesk_size (bnBits(&sec->n));
rsesk = PGPNewData (mgr, rsesksize, 0);
if (IsNull (rsesk)) {
err = kPGPError_OutOfMemory;
goto error;
}
rsesk_initfrom_bn (rsesk, bn, bnBits(&sec->n));
/* Import the blob, decrypting it with the private key */
if (!ex.CryptImportKey (hProv, (BYTE *)rsesk, rsesksize, hKey,
CRYPT_EXPORTABLE, &hSession)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
PGPFreeData (rsesk);
rsesk = NULL;
/* Create a dummy key suitable for clearly exporting the session key */
if (!ex.CryptImportKey (hProv, (BYTE *)&dummyKeyBlob,
sizeof(dummyKeyBlob), 0, 0, &hDummy)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Export session key in the clear as a PKCS1 formatted SIMPLEBLOB */
rsesksize = sizeof (*rsesk) + DUMMYBITS/8;
rsesk = PGPNewData (mgr, rsesksize, 0);
if (IsNull (rsesk)) {
err = kPGPError_OutOfMemory;
goto error;
}
pgpAssert (sizeof(rsesksize) == sizeof(DWORD));
if (!ex.CryptExportKey (hSession, hDummy, SIMPLEBLOB, 0, (BYTE *)rsesk,
&rsesksize)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
pgpAssert (rsesksize == sizeof(*rsesk) + DUMMYBITS/8);
/* Unpack PKCS formatted exported session key and return it */
rseskdata = (PGPByte *)rsesk + sizeof(*rsesk);
bnBegin (&bnsk, mgr, TRUE);
bnInsertLittleBytes (&bnsk, rseskdata, 0, DUMMYBITS/8);
err = (PGPError) pgpPKCSUnpack(outbuf, len, &bnsk, PKCS_PAD_ENCRYPTED,
DUMMYBITS/8);
bnEnd (&bnsk);
error:
if (hSession)
ex.CryptDestroyKey (hSession);
if (hKey)
ex.CryptDestroyKey (hKey);
if (hDummy)
ex.CryptDestroyKey (hDummy);
ex.CryptReleaseContext(hProv, 0);
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if (rsesk) {
pgpClearMemory (rsesk, rsesksize);
PGPFreeData (rsesk);
}
if (rprivk) {
pgpClearMemory (rprivk, rprivksize);
PGPFreeData (rprivk);
}
return err;
}
/*
* Do an RSA signing operation using the secret key on the specified hash
*/
int
rsaSignHash(BigNum *bn, RSAsec const *sec, PGPHashVTBL const *h,
PGPByte const *hash)
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
PRIVATEKEYBLOBHDR *rprivk = NULL;
ALG_ID capihashalg;
PGPUInt32 rprivksize;
PGPByte *sigbuf = NULL;
PGPUInt32 sigsize;
PGPMemoryMgrRef mgr = bn->mgr;
PGPError err = kPGPError_NoErr;
/* SET the return number to 0 to start */
(void)bnSetQ(bn, 0);
if (!(pgpCAPIuse() & PGP_PKUSE_SIGN))
return kPGPError_PublicKeyUnimplemented;
/* CAPI has bugs with keys not mult of 64 bits */
if ((bnBytes(&sec->n) % 8) != 0)
return kPGPError_CAPIUnsupportedKey;
/* Get handle to the base PROV_RSA_FULL provider */
/* Use our reserved container name, always start with an empty one */
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_DEF_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if(!ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Determine what hash algorithm to use */
if (h->algorithm == kPGPHashAlgorithm_MD5) {
capihashalg = CALG_MD5;
} else if (h->algorithm == kPGPHashAlgorithm_MD2) {
capihashalg = CALG_MD2;
} else if (h->algorithm == kPGPHashAlgorithm_SHA) {
capihashalg = CALG_SHA;
} else {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Create and load the hash value */
if (!ex.CryptCreateHash (hProv, capihashalg, 0, 0, &hHash)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
if (!ex.CryptSetHashParam (hHash, HP_HASHVAL, (BYTE *)hash, 0)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Initialize private key structure */
rprivksize = rprivk_size (sec);
rprivk = PGPNewSecureData (mgr, rprivksize, 0);
if (IsNull (rprivk)) {
err = kPGPError_OutOfMemory;
goto error;
}
rprivk_init(rprivk, sec, mgr, TRUE);
/*
* Importing private key into an otherwise empty key container should
* make it be used as the signing key.
*/
if (!ex.CryptImportKey (hProv, (BYTE *)rprivk, rprivksize, 0, 0, &hKey)) {
err = kPGPError_PublicKeyUnimplemented;
goto error;
}
/* Perform the signature operation */
sigsize = bnBytes (&sec->n);
sigbuf = PGPNewData (mgr, sigsize, 0);
if (IsNull (sigbuf)) {
err = kPGPError_OutOfMemory;
goto error;
}
pgpAssert (sizeof(sigsize) == sizeof(DWORD));
if (!ex.CryptSignHash (hHash, AT_SIGNATURE, 0, 0, sigbuf, &sigsize)) {
err = kPGPError_PublicKeyUnimplemented;
sigsize = 0;
goto error;
}
pgpAssert (sigsize = bnBytes(&sec->n));
/* Return in PGP bn format */
bnInsertLittleBytes(bn, sigbuf, 0, sigsize);
error:
if (hKey)
ex.CryptDestroyKey (hKey);
if (hHash)
ex.CryptDestroyHash (hHash);
ex.CryptReleaseContext(hProv, 0);
ex.CryptAcquireContext(&hProv, PGPCONTAINER, MS_ENH_PROV, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
if (sigbuf) {
pgpClearMemory (sigbuf, sigsize);
PGPFreeData (sigbuf);
}
if (rprivk) {
pgpClearMemory (rprivk, rprivksize);
PGPFreeData (rprivk);
}
return err;
}
/*
* Return TRUE if the bignum holding the signature value is valid.
*/
PGPBoolean
rsaVerifyHashSignature(BigNum *bn, RSApub const *pub, PGPHashVTBL const *h,
PGPByte const *hash)
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
PUBLICKEYBLOBHDR *rpubk = NULL;
ALG_ID capihashalg;
PGPUInt32 rpubksize;
PGPByte *sigbuf = NULL;
PGPUInt32 sigsize;
PGPMemoryMgrRef mgr = bn->mgr;
PGPBoolean valid = FALSE;
if (!(pgpCAPIuse() & PGP_PKUSE_SIGN))
return FALSE;
/* Get handle to the base PROV_RSA_FULL provider */
/* Signature verification does not need a key container */
#if PGP_USECAPIFORMD2 /* [ */
if (h->algorithm == kPGPHashAlgorithm_MD2) {
hProv = ((HCRYPTPROV *)hash)[0];
} else
#endif
{
if (!ex.CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
goto error;
}
}
/* Determine what hash algorithm to use */
if (h->algorithm == kPGPHashAlgorithm_MD5) {
capihashalg = CALG_MD5;
} else if (h->algorithm == kPGPHashAlgorithm_MD2) {
capihashalg = CALG_MD2;
} else if (h->algorithm == kPGPHashAlgorithm_SHA) {
capihashalg = CALG_SHA;
} else {
goto error;
}
/* Create and load the hash value */
#if PGP_USECAPIFORMD2 /* [ */
if (h->algorithm == kPGPHashAlgorithm_MD2) {
hHash = ((HCRYPTHASH *)hash)[1];
} else
#endif /* ] */
{
if (!ex.CryptCreateHash (hProv, capihashalg, 0, 0, &hHash)) {
goto error;
}
if (!ex.CryptSetHashParam (hHash, HP_HASHVAL, (BYTE *)hash, 0)) {
goto error;
}
}
/* Initialize and import public key structure */
rpubksize = rpubk_size (pub);
rpubk = PGPNewData (mgr, rpubksize, 0);
if (IsNull (rpubk)) {
goto error;
}
rpubk_init(rpubk, pub);
if (!ex.CryptImportKey (hProv, (BYTE *)rpubk, rpubksize, 0, 0, &hKey)) {
goto error;
}
/* Extract and verify signature */
sigsize = bnBytes(&pub->n);
sigbuf = PGPNewData (mgr, sigsize, 0);
if (IsNull (sigbuf)) {
goto error;
}
bnExtractLittleBytes(bn, sigbuf, 0, sigsize);
valid = ex.CryptVerifySignature (hHash, sigbuf, sigsize, hKey, 0, 0);
error:
if (hKey)
ex.CryptDestroyKey (hKey);
if (hHash)
ex.CryptDestroyHash (hHash);
ex.CryptReleaseContext(hProv, 0);
if (sigbuf) {
pgpClearMemory (sigbuf, sigsize);
PGPFreeData (sigbuf);
}
if (rpubk) {
pgpClearMemory (rpubk, rpubksize);
PGPFreeData (rpubk);
}
return valid;
}
#endif /* ] PGP_USECAPIFORRSA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -