私钥解密代码对 BSAFE 库 v6.0 使用 Public 接口规范?
Private Key Decryption Code Uses Public Interface Specifers to BSAFE Library v6.0?
我最近被赋予了升级一段非常古老的加密代码的责任,该代码在 Windows 10 下将不再 运行。我升级到 Visual Studio 2013,并修改了编写一些代码以使用更好的错误报告。代码工作正常。它使用私钥来解密加密数据。一切都很好。
除了,当时我注意到代码中的一条注释表明某些 PUBLIC 说明符必须用作 BSAFE v6.0 库例程的输入,而不是他们的私人同行。事实上,当使用私有说明符时,我收到以下错误消息:
RSA 错误:密钥信息格式无效
注意:我的私钥没有加密。
我对为什么私有说明符不起作用感到困惑,因为我正在进行私钥解密。
在以下代码中,BSAFE v6.0 库函数是 B_SetKeyInfo、B_GetKeyInfo 和 B_SetAlgorithmInfo 使用 public 键说明符。
int Decrypt(unsigned char* cypherData, const string privKeyFilePathAndName, unsigned char*& plainData) {
enum {
IN_BUF_LEN = 1000, // input buffer length
NUM_DIGITAL_SIGNATURE_BYTES = 128 // number of digital signature bytes
};
static unsigned char decryptedDigest[NUM_DIGITAL_SIGNATURE_BYTES]; // decrypted digest (returned)
const string delimiters = " \n"; // strtok delimeters
A_RSA_KEY privKey; // private key
B_ALGORITHM_OBJ rsaAlgorithmObj; // rsa algorithm object
B_KEY_OBJ privKeyObject; // private key object
char inBuf[IN_BUF_LEN]; // input buffer
char* token; // strtok token
FILE* ifp; // input (private key) file pointer
int i; // index
int stat; // status
unsigned char privModulusData[NUM_MODULUS_BYTES]; // modulus data
unsigned char privExponentData[NUM_MODULUS_BYTES]; // exponent data
unsigned int digestLen; // digest length
unsigned int partOutLen; // part out length
// open private key file
if ((ifp = fopen(privKeyFilePathAndName.c_str(), "r")) == NULL) {
DisplayErrorMsg("Can't open private key file");
return FAIL;
}
// get modulus length and exponent length
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read number of modulus bytes (modulus length)");
return FAIL;
}
privKey.modulus.len = privKey.exponent.len = stoi(inBuf);
// get modulus data
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read modulus data");
return FAIL;
}
token = strtok(inBuf, delimiters.c_str());
for (i = 0; token; i++) {
privModulusData[i] = (unsigned char) stoi(token);
token = strtok(NULL, delimiters.c_str());
}
if (i != sizeof(privModulusData)) {
DisplayErrorMsg("Private key file error - wrong amount of modulus data");
return FAIL;
}
// get exponent data
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read exponent data");
return FAIL;
}
token = strtok(inBuf, delimiters.c_str());
for (i = 0; token; i++) {
privExponentData[i] = (unsigned char) stoi(token);
token = strtok(NULL, delimiters.c_str());
}
if (i != sizeof(privExponentData)) {
DisplayErrorMsg("Private key file error - wrong amount of exponent data");
return FAIL;
}
// close private key file and finish creating private key variable
fclose(ifp);
privKey.modulus.data = privModulusData;
privKey.exponent.data = privExponentData;
// create private key object and set to key read in from file
if ((stat = B_CreateKeyObject(&privKeyObject)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// the private key is set to an Infotype of KI_RSAPublic because an error is
// generated during decryption if we use the Infotype KI_RSAPrivate; not sure
// why it works this way
if ((stat = B_SetKeyInfo(privKeyObject, KI_RSAPublic, (POINTER)&privKey)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_GetKeyInfo((POINTER *)&privKey, privKeyObject, KI_RSAPublic)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// create an rsa algorithm object and set algorithm infoType to RSAPublic
if ((stat = B_CreateAlgorithmObject(&rsaAlgorithmObj)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_SetAlgorithmInfo(rsaAlgorithmObj, AI_RSAPublic, NULL_PTR)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// perform the decryption, in stages (initial, update, and final)
if ((stat = B_DecryptInit(rsaAlgorithmObj, privKeyObject, DEMO_ALGORITHM_CHOOSER, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_DecryptUpdate(rsaAlgorithmObj, decryptedDigest, &digestLen, sizeof(decryptedDigest), cypherData, NUM_DIGITAL_SIGNATURE_BYTES, (B_ALGORITHM_OBJ)NULL_PTR, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_DecryptFinal(rsaAlgorithmObj, decryptedDigest, &partOutLen, sizeof(decryptedDigest), (B_ALGORITHM_OBJ)NULL_PTR, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// set returned pointer and return pass code
plainData = decryptedDigest;
return PASS;
}
RSA BSAFE Crypto-C 5.2 库参考手册指出不建议使用 KI_RSAPrivate。与 RSA 私钥一起使用的正确 KI 是 KI_PKCS_RSAPrivate 和 KI_PKCS_RSAPrivateBER。参见 here。
我最近被赋予了升级一段非常古老的加密代码的责任,该代码在 Windows 10 下将不再 运行。我升级到 Visual Studio 2013,并修改了编写一些代码以使用更好的错误报告。代码工作正常。它使用私钥来解密加密数据。一切都很好。
除了,当时我注意到代码中的一条注释表明某些 PUBLIC 说明符必须用作 BSAFE v6.0 库例程的输入,而不是他们的私人同行。事实上,当使用私有说明符时,我收到以下错误消息:
RSA 错误:密钥信息格式无效
注意:我的私钥没有加密。
我对为什么私有说明符不起作用感到困惑,因为我正在进行私钥解密。
在以下代码中,BSAFE v6.0 库函数是 B_SetKeyInfo、B_GetKeyInfo 和 B_SetAlgorithmInfo 使用 public 键说明符。
int Decrypt(unsigned char* cypherData, const string privKeyFilePathAndName, unsigned char*& plainData) {
enum {
IN_BUF_LEN = 1000, // input buffer length
NUM_DIGITAL_SIGNATURE_BYTES = 128 // number of digital signature bytes
};
static unsigned char decryptedDigest[NUM_DIGITAL_SIGNATURE_BYTES]; // decrypted digest (returned)
const string delimiters = " \n"; // strtok delimeters
A_RSA_KEY privKey; // private key
B_ALGORITHM_OBJ rsaAlgorithmObj; // rsa algorithm object
B_KEY_OBJ privKeyObject; // private key object
char inBuf[IN_BUF_LEN]; // input buffer
char* token; // strtok token
FILE* ifp; // input (private key) file pointer
int i; // index
int stat; // status
unsigned char privModulusData[NUM_MODULUS_BYTES]; // modulus data
unsigned char privExponentData[NUM_MODULUS_BYTES]; // exponent data
unsigned int digestLen; // digest length
unsigned int partOutLen; // part out length
// open private key file
if ((ifp = fopen(privKeyFilePathAndName.c_str(), "r")) == NULL) {
DisplayErrorMsg("Can't open private key file");
return FAIL;
}
// get modulus length and exponent length
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read number of modulus bytes (modulus length)");
return FAIL;
}
privKey.modulus.len = privKey.exponent.len = stoi(inBuf);
// get modulus data
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read modulus data");
return FAIL;
}
token = strtok(inBuf, delimiters.c_str());
for (i = 0; token; i++) {
privModulusData[i] = (unsigned char) stoi(token);
token = strtok(NULL, delimiters.c_str());
}
if (i != sizeof(privModulusData)) {
DisplayErrorMsg("Private key file error - wrong amount of modulus data");
return FAIL;
}
// get exponent data
if ((fgets(inBuf, IN_BUF_LEN, ifp)) == NULL) {
DisplayErrorMsg("Private key file error - can't read exponent data");
return FAIL;
}
token = strtok(inBuf, delimiters.c_str());
for (i = 0; token; i++) {
privExponentData[i] = (unsigned char) stoi(token);
token = strtok(NULL, delimiters.c_str());
}
if (i != sizeof(privExponentData)) {
DisplayErrorMsg("Private key file error - wrong amount of exponent data");
return FAIL;
}
// close private key file and finish creating private key variable
fclose(ifp);
privKey.modulus.data = privModulusData;
privKey.exponent.data = privExponentData;
// create private key object and set to key read in from file
if ((stat = B_CreateKeyObject(&privKeyObject)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// the private key is set to an Infotype of KI_RSAPublic because an error is
// generated during decryption if we use the Infotype KI_RSAPrivate; not sure
// why it works this way
if ((stat = B_SetKeyInfo(privKeyObject, KI_RSAPublic, (POINTER)&privKey)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_GetKeyInfo((POINTER *)&privKey, privKeyObject, KI_RSAPublic)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// create an rsa algorithm object and set algorithm infoType to RSAPublic
if ((stat = B_CreateAlgorithmObject(&rsaAlgorithmObj)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_SetAlgorithmInfo(rsaAlgorithmObj, AI_RSAPublic, NULL_PTR)) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// perform the decryption, in stages (initial, update, and final)
if ((stat = B_DecryptInit(rsaAlgorithmObj, privKeyObject, DEMO_ALGORITHM_CHOOSER, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_DecryptUpdate(rsaAlgorithmObj, decryptedDigest, &digestLen, sizeof(decryptedDigest), cypherData, NUM_DIGITAL_SIGNATURE_BYTES, (B_ALGORITHM_OBJ)NULL_PTR, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
if ((stat = B_DecryptFinal(rsaAlgorithmObj, decryptedDigest, &partOutLen, sizeof(decryptedDigest), (B_ALGORITHM_OBJ)NULL_PTR, ((A_SURRENDER_CTX*)NULL_PTR))) != 0) {
DisplayRsaErrorMsg(stat);
return FAIL;
}
// set returned pointer and return pass code
plainData = decryptedDigest;
return PASS;
}
RSA BSAFE Crypto-C 5.2 库参考手册指出不建议使用 KI_RSAPrivate。与 RSA 私钥一起使用的正确 KI 是 KI_PKCS_RSAPrivate 和 KI_PKCS_RSAPrivateBER。参见 here。