I am trying to generate the payload for a rest API and part of the payload is a digital signature using our private key.
The private key is generated from an external source using openssl, with AES-256 encryption as below:
openssl genrsa -aes256 -passout pass:{password} -out {location} 2048
and then converted to PKCS#8 format also using openssl.
I am using the CrypterObject AsymmetricSign function to generate the signature using the PKCS#8 private key but I get an Invalid privKey error.
Does PB2019 support encrypted private keys for AsymmetricSign? If so, are there additional steps that need to be done before I call this function?
Thanks,
Eric
Below is the sample code:
String ls_private_key_pkcs8
Blob lblb_private_key, lblb_hash, lblb_sign
CrypterObject lnv_CrypterObject
CoderObject lnv_CoderObject
lnv_CrypterObject = Create CrypterObject
lnv_CoderObject = Create CoderObject
ls_private_key_pkcs8 = 'MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI77MkcuVWINQCAggA'
ls_private_key_pkcs8 += 'MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBD3UscJJMjByZaOQnhrEXF1BIIE'
ls_private_key_pkcs8 += '0LygIgD3de0dMf9zvPnaNEMG2JNZow42DQjN7EOo+ni4blH+AgYB1jWzH+1BWkQn'
…
…
…
lblb_private_key = lnv_CoderObject.Base64Decode(ls_private_key_pkcs8)
lblb_hash = lnv_CrypterObject.SHA(SHA256!, Blob('Key=Value', EncodingUTF8!))
lblb_sign = lnv_CrypterObject.AsymmetricSign(RSA!, lblb_hash, lblb_private_key)
The code is fairly simple:
public string SignData(string hashedData, string privateKey)
{
// The array to store the signed message in bytes
byte[] originalData;
byte[] signedBytes;
int bytesRead;
//Convert hashedData in Base64 to byte array
originalData = Convert.FromBase64String(hashedData);
using (var rsa = RSA.Create())
{
// Import the private key used for signing the message
bool isPkcsprivateKey = privateKey.Contains("BEGIN PRIVATE KEY");
if (isPkcsprivateKey)
{
privateKey = privateKey.Replace("-----BEGIN PRIVATE KEY-----", string.Empty).Replace("-----END PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out bytesRead);
}
else
{
privateKey = privateKey.Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty).Replace("-----END RSA PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
rsa.ImportRSAPrivateKey(privateKeyBytes, out bytesRead);
}
// Sign the hashed data
signedBytes = rsa.SignHash(originalData, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
// Convert the byte array to a base64url string before returning
return Convert.ToBase64String(signedBytes)
.Replace('+', '-') // replace URL unsafe characters with safe ones
.Replace('/', '_') // replace URL unsafe characters with safe ones
.Replace("=", ""); // no padding
}
}
public string RS256 (string unsignedData, string privateKey)
{
byte[] msgBytes = Encoding.UTF8.GetBytes(unsignedData);
ISigner signer = SignerUtilities.GetSigner(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id);
privateKey = privateKey.Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty).Replace("-----END RSA PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
var privKeyObj = Asn1Object.FromByteArray(privateKeyBytes);
var privStruct = RsaPrivateKeyStructure.GetInstance((Asn1Sequence)privKeyObj);
signer.Init(true, new RsaKeyParameters(true, privStruct.Modulus, privStruct.PrivateExponent));
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
byte[] sigBytes = signer.GenerateSignature();
return Convert.ToBase64String(sigBytes)
.Replace('+', '-') // replace URL unsafe characters with safe ones
.Replace('/', '_') // replace URL unsafe characters with safe ones
.Replace("=", ""); // no padding
}
I'll post it up in the CodeXchange section sometime tomorrow. You just run the .Net DLL importer on the assembly, pass in the data and your private key and you'll get the base64urlencoded signature data out.
I'm doing base64urlencodd because I'm using it for JWT. What format are you looking for?
https://community.appeon.com/index.php/codeexchange/powerbuilder/266-rs256-encryption-using-bouncy-castle-through-net-assembly-import