Verify RSA signature in openssl0.9.8a - rsa

I'm developping a C++ application based on openssl0.9.8a API, i need to verify an RSA signature (4096 bit RSA key) using an RSA public key "pubkey"
const EVP_MD* md = EVP_get_digestbyname("SHA512");
if (!md) return false;
if(EVP_DigestInit_ex(ctx, md, NULL)<=0) return false;
if(EVP_DigestVerifyInit( ctx, NULL, md, NULL, pubKey)<=0) return false;
if (EVP_DigestUpdate(ctx, Msg, MsgLen) <= 0) return false;
int res = EVP_DigestFinal_ex(ctx, MsgHash, &MsgHashLen);
The problem is "EVP_DigestVerifyInit" function is not defined in openssl0.9.8a, is there any other alternative? Is there an other way to verify an RSA signature in openssl0.9.8a?

Related

How to encrypt data in one app and decrypt it in different Windows app with RSA keys tied to local system?

I have a setup where I need to encrypt blob of data in one app and decrypt it in different app.
I built a sample app that creates a named CngKey object. Then create a RSACng using CngKey object. Then use RSACng object to do encryption/decryption. What I found is that the key changes across restarts of the application even though it is loaded using the name it was created with. I am lost trying to understand the relation between CngKey and RSACng objects.
Below is snippet of code that describes what I am trying to do:
using System;
using System.IO;
using System.Security.Cryptography;
namespace TPMCrypto
{
class Program
{
static byte[] data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
static byte[] privateKey;
private static byte[] encrypted;
private static byte[] decrypted;
static void Main(string[] args)
{
const string MyKey = "MyRSAKey";
CngKey cngKey = null;
string cmd = args.Length > 0 ? args[0] : "";
try
{
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider
};
if (!CngKey.Exists(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey))
{
Console.WriteLine("Creating rsaKey");
cngKey = CngKey.Create(CngAlgorithm.Rsa, MyKey, cng);
}
else
{
Console.WriteLine("Opening rsaKey");
cngKey = CngKey.Open(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey);
}
RSACng rsaKey = new RSACng(cngKey)
{
KeySize = 2048
};
privateKey = rsaKey.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
string prvResult = ByteArrayToHexString(privateKey, 0, privateKey.Length);
Console.WriteLine("\nPrivate key - length = " + privateKey.Length + "\n" + prvResult + "\n");
const string FILE_PATH = #"\temp\tpmtests\encryptedblob.dat";
// Encrypt / decrypt
if (cmd == "readfromfile")
{
Directory.CreateDirectory(Path.GetDirectoryName(FILE_PATH));
encrypted = File.ReadAllBytes(FILE_PATH);
}
else if (cmd == "deletekey")
{
cngKey.Delete();
return;
}
else
{
encrypted = Encrypt(rsaKey, data);
Console.WriteLine("The encrypted blob: ");
Console.WriteLine(ByteArrayToHexString(encrypted, 0, encrypted.Length));
File.WriteAllBytes(FILE_PATH, encrypted);
}
decrypted = Decrypt(rsaKey, encrypted);
bool result = ByteArrayCompare(data, decrypted);
if (result)
Console.WriteLine("Encrypt / decrypt works");
else
Console.WriteLine("Encrypt / decrypt fails");
}
catch (Exception e)
{
Console.WriteLine("Exception " + e.Message);
}
finally
{
if (cngKey != null)
cngKey.Dispose();
}
Console.ReadLine();
}
static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
if (a1[i] != a2[i])
return false;
return true;
}
public static string ByteArrayToHexString(byte[] bytes, int start, int length)
{
string delimitedStringValue = BitConverter.ToString(bytes, start, length);
return delimitedStringValue.Replace("-", "");
}
public static byte[] Sign512(byte[] data, byte[] privateKey)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
return crypto.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static bool VerifySignature512(byte[] data, byte[] signature, byte[] publicKey)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
return crypto.VerifyData(data, signature, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static byte[] Encrypt(byte[] publicKey, byte[] data)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
var result = Encrypt(crypto, data);
return result;
}
public static byte[] Encrypt(RSACng crypto, byte[] data)
{
if (null == crypto)
return null;
var result = crypto.Encrypt(data, RSAEncryptionPadding.OaepSHA512);
return result;
}
public static byte[] Decrypt(byte[] privateKey, byte[] data)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
var result = Decrypt(crypto, data);
return result;
}
public static byte[] Decrypt(RSACng aKey, byte[] data)
{
if (null == aKey)
return null;
var result = aKey.Decrypt(data, RSAEncryptionPadding.OaepSHA512);
return result;
}
}
}
I am aware of dpapi and how to do this using it. I don't want to use it for this, please don't point me in that direction. I am using CNG flavor of crypto to force C# use NCryptXYZ crypto calls and the desire is to secure the keys in TPM.
Ah, looking at your code again, you've made a goof.
RSACng rsaKey = new RSACng(cngKey)
{
KeySize = 2048
};
Setting the KeySize property on an RSACng does one of two things:
If get_KeySize == value, ignore the input, do nothing.
Else, detach from the current key and the next time the key is used, generate a new key of get_KeySize at the time.
So you're opening an existing key, then discarding it, and generating a new ephemeral key. (Which you could see by checking rsaKey.Key.Name, it won't match your input).
Presumably you did this as a way to create the key with the right size in the first place, but you're too late. The correct way is
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
Parameters =
{
new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.Persist),
},
};

AWS cloudhsm with PKCS#11 not able to export RSA public key

I am generating a RSA key pair with AWS cloud HSM with PKCS11Interop c# library on top of AWS vendor PKCS library. Wanted to export a public key from HSM with PKCS 11 getAttributeValue methods.
The response states that attributes cannot be read, I have marked all the attributes values correctly to be able to export a key, can somebody point out what I am doing wrong ?
My sample code
private static void GenerateRSAKeyPair(ISession session, out IObjectHandle publicKeyHandle, out IObjectHandle privateKeyHandle, string keyAlias = null)
{
byte[] ckaId = null;
if (string.IsNullOrEmpty(keyAlias))
ckaId = session.GenerateRandom(20);
else
ckaId = Encoding.UTF8.GetBytes(keyAlias);
// Prepare attribute template of new public key
List<IObjectAttribute> publicKeyAttributes = new List<IObjectAttribute>();
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY));
//publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, false)); // Throws InvalidAttribute Value
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_WRAP, true));
//publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODULUS_BITS, 2048));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PUBLIC_EXPONENT, new byte[] { 0x01, 0x00, 0x01 }));
// Prepare attribute template of new private key
List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
//privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true));
//publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_UNWRAP, true));
// Specify key generation mechanism
IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_X9_31_KEY_PAIR_GEN);
// Generate key pair
session.GenerateKeyPair(mechanism, publicKeyAttributes, privateKeyAttributes, out publicKeyHandle, out privateKeyHandle);
}
private static byte[] GetKeyAttributeValue(ISession session, IObjectHandle keyHandle)
{
var readAttrs = session.GetAttributeValue(keyHandle, new List<CKA>() { CKA.CKA_VALUE });
if (readAttrs[0].CannotBeRead)
throw new Exception("Key cannot be exported");
else
return readAttrs[0].GetValueAsByteArray();
}
RSA public key objects do not have CKA_VALUE attribute. Instead, there are two attributes called CKA_MODULUS and CKA_PUBLIC_EXPONENT that make up the key value.
As suggested by #Homaei
I have created below code to export a public key from c# code.
var modulus = GetKeyAttributeValue(session, publicKey, CKA.CKA_MODULUS);
var exponent = GetKeyAttributeValue(session, publicKey, CKA.CKA_PUBLIC_EXPONENT);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(dwKeySize: 2048);
RSAParameters rsaParam = rsa.ExportParameters(false);
rsaParam.Modulus = modulus;
rsaParam.Exponent = exponent;
rsa.ImportParameters(rsaParam);
var writer = System.IO.File.CreateText("exportedFromCode.txt");
//https://stackoverflow.com/questions/28406888/c-sharp-rsa-public-key-output-not-correct/28407693#28407693
ExportPublicKey(rsa, writer);

AES Encryption and decryption using jks file

I have one small doubt as i am new to AES.
I encrypted a string using one certificate with some password lets say , 'xxx'.
Now i duplicated the certificate by changing the password of it.
When i try to decrypt the encrypted string with the duplicated cert, it says Bad padding exception.Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
However, when i use the original cert, it decrypts properly.
Could anyone please guide me on it?
public SecretKey retrieveKey(String password, byte[] certFile) throws Exception {
try {
String alias = null;
certPass = password;
char[] pass = certPass.toCharArray();
KeyStore keyStore = KeyStore.getInstance("jceks");
InputStream inputStream = new ByteArrayInputStream(certFile);
keyStore.load(inputStream, pass);
Enumeration enumeration = keyStore.aliases();
while (enumeration.hasMoreElements()) {
alias = (String) enumeration.nextElement();
}
Certificate cert = keyStore.getCertificate(alias);
Key key = cert.getPublicKey();
aesSecretKey = new SecretKeySpec(key.getEncoded(), algorithm);
byte[] encoded = aesSecretKey.getEncoded();
byte[] encryptionKey = Arrays.copyOfRange(encoded, encoded.length - 16, encoded.length);
aesSecretKey = new SecretKeySpec(encryptionKey, algorithm);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw e;
}
return aesSecretKey;
}
You should use RSA to wrap / unwrap the AES key. The public key is not identical to the AES key, so the following code is certainly incorrect:
Key key = cert.getPublicKey();
aesSecretKey = new SecretKeySpec(key.getEncoded(), algorithm);

Swift Biginteger xor encrypt/decrypt

I'm new to Swift, now I just want to translate java xor encrypt/decrypt code to Swift, which is used for transactions between server and client. Below is the Java xor code:
public static String encrypt(String password, String key) {
if (password == null)
return "";
if (password.length() == 0)
return "";
BigInteger bi_passwd = new BigInteger(password.getBytes());
BigInteger bi_r0 = new BigInteger(key);
BigInteger bi_r1 = bi_r0.xor(bi_passwd);
return bi_r1.toString(16);
}
public static String decrypt(String encrypted, String key) {
if (encrypted == null)
return "";
if (encrypted.length() == 0)
return "";
BigInteger bi_confuse = new BigInteger(key);
try {
BigInteger bi_r1 = new BigInteger(encrypted, 16);
BigInteger bi_r0 = bi_r1.xor(bi_confuse);
return new String(bi_r0.toByteArray());
} catch (Exception e) {
return "";
}
}
And I've searched a lot about swift xor encryption and tried the answer in the links below:
XOR Encryption in Swift IOS
https://coderwall.com/p/timkvw/simple-xor-encryption-and-decryption-in-swift-playground-code
Swift Simple XOR Encryption
But all of them can't get the same encryted string compared with my java code, now my java code was live, and there's no way to change it.
I thought it might caused by the hexadecimal, but in swift, I can't find anywhere about swift xor hexadecimal.
So what I need is the swift code can get the exact same encrypted string as java code I've pasted, the encrypted string generated by my java client can be decrypted in my iOS client.
Thanks very much whoever can help me out of this! I've get into this a whole day!
Thanks again.
Solved, below is the code.
Based on the great work at https://github.com/lorentey/BigInt
func encrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str.data(using: String.Encoding.utf8)!)
let encrypt = key ^ value
return String(encrypt, radix: 16)
}
func decrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str, radix: 16)!
let decrypt = key ^ value
return String(data: decrypt.serialize(), encoding: String.Encoding.utf8)!
}
Thanks again for everyone whoever contributed to the the BigInt library, that's why the code looks so simple.

Why does Bouncy Castle RSAEngine.processblock method always returns 255 bytes when decrypting?

I am experiment with RSA using bouncy castle. I know this is the other way around to the general convention but to my understanding, it still should work theoretically.
I encrypt some data using an RSA private key. The length of the data being encrypted is 294 bytes. The encryption function outputs 512 bytes. I then call the decryption method by passing the above output cipher text and the corresponding public key. My problem is that the decryption always returns a buffer of 255 bytes whereas the actual input to the Encryption function was 294 bytes. What could be the reason for this ?
The following is the source code of the encryption and decryption functions.
public static byte[] RSAEncrypt(byte[] data, AsymmetricKeyParameter key)
{
try
{
RsaEngine e = new RsaEngine();
e.Init(true, key);
int blockSize = e.GetInputBlockSize();
List<byte> output = new List<byte>();
for (int chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, data.Length - (chunkPosition * blockSize));
output.AddRange(e.ProcessBlock(data, chunkPosition, chunkSize));
}
return output.ToArray();
}
catch (Exception ex)
{
return null;
}
}
public static byte[] RSADecrypt(byte[] data, AsymmetricKeyParameter key)
{
try
{
RsaEngine e = new RsaEngine();
e.Init(false, key);
int blockSize = e.GetInputBlockSize();
List<byte> output = new List<byte>();
for (int chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, data.Length - (chunkPosition * blockSize));
output.AddRange(e.ProcessBlock(data, chunkPosition, chunkSize));
}
return output.ToArray();
}
catch (Exception ex)
{
return null;
}
}
RSA is an asymmetric encryption method that encrypts a number less than the modulus of the RSA key (255 bytes would indicate that you're using a 256*8 = 2048 bit RSA key/modulus)
What you need to do to encrypt values greater than that is to generate a key, encrypt the data using a symmetric cipher (AES is not a bad choice) and encrypt the AES key using your private RSA key (preferably along with some other random data).
The AES key is a maximum of 256 bits, which will encrypt just fine with RSA, and AES does not have a size limit.