How to convert JAVA program to PHP to carryout RSA encryption - java

I am trying to implement AEPS API but unable to encrypt aadhar number in php. In developer guide they provided method to encrypt using JAVA and i am using php.
Given JAVA code is as follows.
public static String calculateRSA( String salt ) throws InvalidKeyException, Exception {
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
byte[] secretMessageBytes = salt.getBytes("UTF-8");
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
String encodedMessage = Base64.encodeBase64String(encryptedMessageBytes);
return encodedMessage;
}
public static PublicKey getPublicKey() throws Exception {
String rawPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaFyrzeDhMaFLx+LZUNOOO14Pj9aPfr+1WOanDgDHxo9NekENYcWUftM9Y17ul2pXr3bqw0GCh4uxNoTQ5cTH4buI42LI8ibMaf7Kppq9MzdzI9/7pOffgdSn+P8J64CJAk3VrVswVgfy8lABt7fL8R6XReI9x8ewwKHhCRTwBgQIDAQAB";
byte[] keyBytes = Base64.decodeBase64(rawPublicKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);// generatePrivate(spec);
}
I tried
$publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaFyrzeDhMaFLx+LZUNOOO14Pj9aPfr+1WOanDgDHxo9NekENYcWUftM9Y17ul2pXr3bqw0GCh4uxNoTQ5cTH4buI42LI8ibMaf7Kppq9MzdzI9/7pOffgdSn+P8J64CJAk3VrVswVgfy8lABt7fL8R6XReI9x8ewwKHhCRTwBgQIDAQAB';
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey($publicKey); // public key
$plaintext = '828409353766';
//$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$encrypted = $rsa->encrypt($plaintext);
$encrypted = base64_encode($encrypted);

Related

AES 256 GCM Java Implementation

I'm trying to rewrite the following implementation of AES-256-GCM encryption from NodeJS to Java.
Packet description
Im getting a different output, specifically the auth tag part. From the looks of it, the Java libs dont have any methods to fetch the auth tag, and my attempt to substring it from the output fails. Also, I'm not actually sure that the first AES encryption with the public key (generating a random buffer for GCM) works the same as the NodeJS counterpart.
Can anyone point me in the right direction?
NodeJS:
public encryptPassword(password: string, encryptionKey: string, encryptionKeyId: string): { time: string, encrypted: string } {
const randKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(12);
const rsaEncrypted = crypto.publicEncrypt({
key: Buffer.from(encryptionKey, 'base64').toString(),
// #ts-ignore
padding: crypto.constants.RSA_PKCS1_PADDING,
}, randKey);
const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
const time = Math.floor(Date.now() / 1000).toString();
cipher.setAAD(Buffer.from(time));
const aesEncrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
const sizeBuffer = Buffer.alloc(2, 0);
sizeBuffer.writeInt16LE(rsaEncrypted.byteLength, 0);
const authTag = cipher.getAuthTag();
return {
time,
encrypted: Buffer.concat([
Buffer.from([1, encryptionKeyId]),
iv,
sizeBuffer,
rsaEncrypted, authTag, aesEncrypted])
.toString('base64'),
};
}
Java:
private static Pair<Long, String> encryptPaswword(String password, String encryptionPubKey, String encryptionKeyId) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidCipherTextException, InvalidAlgorithmParameterException {
byte[] passwordAsByte = password.getBytes();
String decoededPubKey = new String(Base64.decode(encryptionPubKey, Base64.NO_WRAP), StandardCharsets.UTF_8);
decoededPubKey = decoededPubKey.replace("-----BEGIN PUBLIC KEY-----", "");
decoededPubKey = decoededPubKey.replace("-----END PUBLIC KEY-----", "");
SecureRandom random = new SecureRandom();
byte[] randKey = new byte[32];
random.nextBytes(randKey);
byte[] iv = new byte[12];
random.nextBytes(iv);
long date = new Date().getTime() / 1000;
ByteBuffer header = ByteBuffer.allocate(2);
header.put(Integer.valueOf(1).byteValue());
header.put(Integer.valueOf(Integer.parseInt(encryptionKeyId)).byteValue());
ByteBuffer timeAAD = ByteBuffer.allocate(10);
timeAAD.put(String.valueOf(date).getBytes());
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(decoededPubKey, Base64.NO_WRAP));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] rsaEncrypted = rsaCipher.doFinal(randKey);
ByteBuffer sizeBuff = ByteBuffer.allocate(2);
sizeBuff.put(Integer.valueOf(rsaEncrypted.length).byteValue());
final Cipher gcmCipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
gcmCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(randKey, "AES"), parameterSpec);
gcmCipher.updateAAD(timeAAD);
byte[] gcmText= gcmCipher.doFinal(passwordAsByte);
ByteBuffer result = ByteBuffer.allocate(2+12+2+256+gcmText.length);
result.put(header);
result.put(iv);
result.put(sizeBuff);
result.put(rsaEncrypted);
result.put(Arrays.copyOfRange(gcmText, gcmText.length - (16 / Byte.SIZE), gcmText.length));
result.put(Arrays.copyOfRange(gcmText, 0, gcmText.length - (16 / Byte.SIZE)));
return new Pair(new Long(date), Base64.encodeToString(result.array(), Base64.NO_WRAP));

C# How ro get X509 PublicKey from byte stream

Trying to get X509 PublicKey from byte stream using this code.
[Fact]
public void CreatePublicKeyParameters__ShouldReturnPublicKey__WhenPassPublicKeyBytes()
{
ApplePay applePay = new ApplePay(new MOBSHOPApplePayRequest());
byte[] privateKey = Base64.Decode("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjyo3fzxT7j+CFxC7I4B5iVee2FUyn2vfOSjcgp2/g6qhRANCAARdoBFEtnuapXFKw4DYWsW0yV4bavpdWKszkefi19AhlIRE3WSNWSn25W5tZNFjMWtLISBmqANyufx2xP19oRvy");
var publickey = applePay.CreatePublicKeyParameters(privateKey);
}
public AsymmetricKeyParameter CreatePublicKeyParameters(byte[] ephemeralPublicKeyBytes)
{
return (ECPublicKeyParameters)PublicKeyFactory.CreateKey(ephemeralPublicKeyBytes);
}
Getting following error
Bad sequence size: 3
Parameter name: seq
BouncyCastle.Crypto
at Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo..ctor(Asn1Sequence seq)
at Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.GetInstance(Object obj)
at Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(Byte[] keyInfoData)
Basically, I'm trying to convert this following JAVA code to C#
public ECPublicKey CreatePublicKeyParameters(byte[] ephemeralPublicKeyBytes)
{
KeyFactory keyFactory = KeyFactory.getInstance( "ECDH", "BC" );
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec( ephemeralPublicKeyBytes );
ECPublicKey ephemeralPublicKey = (ECPublicKey) keyFactory.generatePublic( encodedKeySpec );
return ECPublicKey
}
Please help me.
Sorry, it was wrong test input data. It's working with this below testcase.
[Fact]
public void CreatePublicKeyParameters__ShouldReturnPublicKey__WhenPassPublicKeyBytes()
{
ApplePay applePay = new ApplePay(new MOBSHOPApplePayRequest());
byte[] privateKey = Base64.Decode(
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl/XAbOgrSCupps/QbIxJ3u4QZ1PlbO5uGDD1zj/JGMoephYSEgw+63gHQHekx3T8duXN3CoYafUpuQlwOeK6/w==");
var publickey = applePay.CreatePublicKeyParameters(privateKey);
}
Thanks

.NET equivalent of Java KeyFactory.getInstance "RSA"/"RSA/ECB/PKCS1Padding"

I have the following code,
public static String encrypt(String plainText, String key){
try{
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeToString(cipher.doFinal(plainText.getBytes("UTF-8")),Base64.DEFAULT);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
I want to convert this to C#. I have tried CryptUtils but it doesn't work https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/CryptUtils.cs
Sample key,
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ9AMIIBCgKCAQEAoqB1N9kugk4UKYnbh0fcg3qYyYKP0m4B
MjWd05ReeAdj+7JRYDEKO6xthDdVSdRO1/2V+YtY8DnXWnxRaICwu8235s3imZCyqgYnomPWdY+F
K540oTz/zug+9wbrlzt/WQFUU4lPlQbzm/Gjw8XfaCozT0e3bnWQcD7rORCOyuJgwSGgREjTv1ss
pgEaKTMknii9vpGZLeAXwoeIYROhuT4IoIkPDhtY0/UZiCi6v7Ja2dmy53VlWIkcm3rcnSJdvpXr
OgiHvaNABHmeymNycNqd6WUaysBRheluQ86nq/2nZPW0gcvmYt5zbMMYX3yY/n2WtAKeNQBAEW1q
b0s6MwIDAQAB
Possible encryped value,
Y3VTjghDnTrCeG8C/RklKsJ3Y0Mt89sSGGin28E4iQPQvKqeZBws7rBQEZaRamDWftxCkEYZs4Qh
V2l4IVlrawdtRmQlcQh8McrpqP/97Gz8pEDEYnqA7kqBTqZw0Z5o0WsshGSwiAQ9wNSym4xHejkq
zrKxWP8XCMkcT0NlKlRMoqKKICFKZbqWeSQkQM5y9OEcmB6inNNkJCoM1Ip48+cK3cOE6dqXNVrl
sSTZ8WQKwoB3dJmcYqexR3kAvBYdX6ZxEF+2+6b9h8+tc5G7Y5R2eqycyUossdkCcI3fNVhyc72P
axCjZFWZUgfDGCxg1WNhStrH9L8c59P35JKKug==
Since i don't have the private key, i can't decrypt, but at least this produces the right lengthed values.
So try this (you need bouncycastle for reading pem):
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
var keyBytes =
Convert.FromBase64String(
"MIIBI...."); // your key here
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
byte[] plaintext = Encoding.UTF8.GetBytes("amount=1&currency=AED");
byte[] ciphertext = rsa.Encrypt(plaintext, false);
string cipherresult = Convert.ToBase64String(ciphertext);

Invalid Cipher bytes in Encryption method in Android using RSA

We are facing an issue while trying to Encrypt data in Android and Decrypt it in a WCF Service. The Android code to encrypt data is as follows:
try{
String strModulus = "tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=";
String strExponent = "AQAB";
byte[] modulusBytes = Base64.decode(strModulus, Base64.DEFAULT);
byte[] exponentBytes = Base64.decode(strExponent, Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA/ECB/PKCS1Padding");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("Manchester United").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
encryptedString = Base64.encodeToString(cipherData, Base64.DEFAULT);
}
catch(Exception e){
Log.e("Error", e.toString());
}
return encryptedString;
The same code in Java:
try{
String strModulus = "tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZHG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=";
String strExponent = "AQAB";
byte[] modulusBytes = DatatypeConverter.parseBase64Binary("tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=");
byte[] exponentBytes = DatatypeConverter.parseBase64Binary("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("Manchester United").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
//String encryptedString = Base64.encodeToString(cipherData, Base64.NO_PADDING);
String encryptedString = DatatypeConverter.printBase64Binary(cipherData);
String encryptedData = encryptedString;
}
catch(Exception e){
}
}
WCF Service:
public string Decrypt()
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=</Modulus><Exponent>AQAB</Exponent><P>6e0nv7EBFBugtpoB+ozpg1J4js8E+DVyWCuBsERBPzqu4H7Z/oeLIRSC8Gi5GZgrCpBf3EvyIluM7rzaIfNThQ==</P><Q>x/29X9ns1WcXC42IJjLDjscz5ygdVh79dm8B2tQVbqwyhDsQ6OIOQdu5+eHf4hUMoTrM9KkS2F6FGlLXuaOFoQ==</Q><DP>kTS2LMaJ/dpce5zDx6w6s1q5HSSiWBSNIu/2s9zah448yXvUg6vNkD40PVk0NRAA/7C44H2AExWzOOqfmN17JQ==</DP><DQ>xtAx9drQPWnpl/uQUOEAVa0kpPTVDStrr9Q1FNTnpYkcAyYw7kLkB4anAIoSpk9kqdeprsNxz5VPXtbiTFMKYQ==</DQ><InverseQ>O0594NMjnjSp+/NAa1kQxoQNzn1qqq+p1Zb+kT3/jRc/0d7ZnqSSpxFMXfxx3yZkNAOPDOdbckPQbRZ13RKBHg==</InverseQ><D>bjVEagwvkrZaTt9CTW1hd3362weLFlX6DpE/3R3RcrpVfkSwKGpEhqGrNeeGPlsuqiaf5rAFir4eTqrF1QVliKsU4XE0RyzP5lHGc7dlX4DOHMjs2R9nNWv8QOTPoaRuLrLGorqBXlw/jQPxFI6gQzkIIjzuf//lDVnFam3dw4E=</D></RSAKeyValue>");
string data2Decrypt = "LyVNDhkdJ5jNgwZDiVZ1R0lmd10AQgqNDFHh2vJB1676eg8wj0MOdTyChAGrvEjha0uXg+f/aNBAc4+/LFbCgsA1e+O3wnXr27sXznGJ9G15avZzQHG4JWUS42MXBahAkcJ80pcihTbL9edfQCkEuj9RzQ/zFJyDEMssfd/EPDM=";
byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);
byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);
}
Original Data : 'Manchester United'
The strange thing is that if I encrypt a string with the Java code it can be decrypted at the WCF service end, however, if it is encrypted using the above Android code, the decryption provides the error: "The data to be decrypted exceeds the maximum for this modulus of 128 bytes".
On debugging, I realized that the byte[] cipherData is not the same for Android and Java. All the previous values happen to be in sync. This generates different Encrypted Strings in Java and Android.
My question is why does this happen? Is there a silly mistake? Is there a way to work around it? Or something else that can be done in Android to get the 'Cipher Data' right?
Any help will be appreciated.
You are using a different padding on Android. Use the exact same padding on Android as well:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

Why always give me false in signature?

I try in this code to verify my code, I have public key , my data and signature.I am read my signature from file and convert my string to public key then get my data and verify to signature.
public static boolean verify () {
String publickey = "MIGfMA0GCSqGSIb3DQE";
byte[] encKey = Base64.decodeBase64(publickey.getBytes());
try {
byte[] MACaddress = GetData();
BufferedReader in = new BufferedReader(new FileReader(
"EndSignatuer.txt"));
FileInputStream keyfis = new FileInputStream("EndSignatuer.txt");
byte[] Signen = new byte[keyfis.available()];
keyfis.read(Signen);
keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] deSignen = Base64.decodeBase64(Signen);
byte[] decrypted_digest = cipher.doFinal(deSignen);
MessageDigest md5_digest = MessageDigest.getInstance("MD5");
md5_digest.update(MACaddress);
byte[] digest = md5_digest.digest();
if (decrypted_digest == digest) {
return true;
}else {
return false;//her why give me false
}
Code encryption:
public static void GenarationKEY(byte[] data) {
try {
File fileEndSignatuer = new File("EndSignatuer.txt");
FileOutputStream fopEndSignatuer = new FileOutputStream(
fileEndSignatuer);
// /Read private key from file
FileInputStream keyfis = new FileInputStream("PiveteKey.txt");
byte[] PrivateKeyB = new byte[keyfis.available()];
keyfis.read(PrivateKeyB);
keyfis.close();
byte[] decodePrivetekey = Base64.decodeBase64(PrivateKeyB);
// /get private key
PKCS8EncodedKeySpec pubKeySpec = new PKCS8EncodedKeySpec(
decodePrivetekey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(pubKeySpec);
// / make hash
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privKey);
// /make encoding
MessageDigest md5_digest = MessageDigest.getInstance("MD5");
byte[] digest = md5_digest.digest(data);
byte[] cipherText = cipher.doFinal(digest);
byte[] degnatureencode = Base64.encodeBase64(cipherText);
fopEndSignatuer.write(degnatureencode);
fopEndSignatuer.flush();
fopEndSignatuer.close();
}
First of all, what you do is not quite RSA digital signature. Use Signature class instead of combination Cipher and MessageDigest. Or if you insist to do it on low level, then consult specification, particularly section 9.2.
Secondly, string MIGfMA0GCSqGSIb3DQE doesn't represent RSA public key neither it is proper Base64-encoded data.
Also you want to use Arrays.equals(byte[], byte[]) instead of equality operator, as the latter just ensures that array object is the same, while the former compares actual content of the arrays.

Categories