BadPaddingException decrypting the encrypted data in Android - java

I'm new to Android security concepts.
I have been reading some blogs to get to know about we can encrypt data using Public key and can decrypt it using respective Private key. Encryption seems to be doesn't have any problem, but when I try to decrypt it, it throws:
javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02.
My code is as follows:
public String RSAEncrypt(final String plain, PublicKey publicKey ) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte [] encryptedBytes = cipher.doFinal(plain.getBytes());
String encrypted = bytesToString(encryptedBytes);
System.out.println("EEncrypted?????" + encrypted );
return encrypted;
}
public String RSADecrypt(String encryptedBytes,PrivateKey privateKey ) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
byte [] decryptedBytes = cipher1.doFinal(stringToBytes(encryptedBytes));
String decrypted = new String(decryptedBytes);
System.out.println("DDecrypted?????" + decrypted);
return decrypted;
}
public String bytesToString(byte[] b) {
byte[] b2 = new byte[b.length + 1];
b2[0] = 1;
System.arraycopy(b, 0, b2, 1, b.length);
return new BigInteger(b2).toString(36);
}
public byte[] stringToBytes(String s) {
byte[] b2 = new BigInteger(s, 36).toByteArray();
return Arrays.copyOfRange(b2, 1, b2.length);
}
Stack trace is as follows:
07-28 11:27:35.119: I/System.out(22933): KEYSTORE : String to encrypt = > Hello
07-28 11:27:35.119: I/System.out(22933): KEYSTORE : [B#41bbf4d0
07-28 11:27:38.422: I/System.out(22933): KEYSTORE : String to Decrypt = > UJGAchuDhu3mqH5YPjmYqKBapJYMjJRk9g6HIy8bANooWorzwqgiEo+dOse6Nfq7i0yzw/Wt7TSdTNiYROxehkZvEx/mW5+Niw1CgZ2y9b/ijTeNTF+7aGPrqfDXJ38hUFdTPc6oNl2FVOIafncGOSK9po1JOAYeK0JiA2KrACfPLPjsLQSRzseThyYGxttRM7qbx/N0VTmlTeuNpLFld8Gtw3fHR8UoLGkH/OTFYPLZBVNE8t/oCCy8FpcCu9SGXxF8vh1R4rq15bfyyh9sBU9RuVtoLM0wDSbKixHhNOwwx2Z/A+SHDaQD9C+x3p1AnS9FYZm0Y07E+VYQWqzOpw
07-28 11:27:38.562: W/System.err(22933): javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
07-28 11:27:41.515: D/WifiNative-wlan0(773): doString: SIGNAL_POLL
07-28 11:27:41.515: W/WifiHW(773): QCOM Debug wifi_send_command "IFNAME=wlan0 SIGNAL_POLL"
07-28 11:27:41.525: D/wpa_supplicant(16189): nl80211: survey data missing!
07-2
07-28 11:27:56.612: W/WifiHW(773): QCOM Debug wifi_send_command "IFNAME=wlan0 SIGNAL_POLL"
07-28 11:27:56.612: D/wpa_supplicant(16189): nl80211: survey data missing!
07-28 11:27:56.622: I/wpa_supplicant(16189): environment dirty rate=0 [0][0][0]
07-28 11:27:56.622: D/WifiStateMachine(773): fetchRssiAndLinkSpeedNative RSSI = -62 abnormalRssiCnt = 0 newLinkSpeed = 58
07-28 11:27:56.622: D/WifiStateMachine(773): fetchRssiAndLinkSpeedNative mLinkspeedCount = 2, mLinkspeedSum: 116
I'm not sure where am going wrong.

A BadPaddingException occurs when the padding (bytes to fill up a too small encryption block) doesn't match a specified format (for example PKCS1, OAEP, ...). This can have a few causes:
You are using a different mode of RSA for en- and decryption.
The data (the byte[]) you get from encryption is not the same as the one you pass to decryption.
(You are using an incorrect KeyPair.)
Since you are initializing RSA with getInstance("RSA") for encryption and getInstance("RSA/ECB/PKCS1Padding") for decryption, it could be possible that ECB/PKCS1Padding is not the default on Android (even though it should be on Desktop-Java).
So try this in RSAEncrypt():
cipher.getInstance("RSA/ECB/PKCS1Padding");
If this does not work, make sure that you pass the exact same byte[] you get from cipher.doFinal() in encryption to cipher.doFinal() in decryption.
(Your code does work on my Desktop Java7 btw.)

you must break message to blocks.
can use below class.
// Note: RSA has block limitation, text size must < (SIZE/8) , otherwise you see [too much data for RSA block]
public class RSA
{
private RSAPublicKey internalPublicKey;
private RSAPrivateCrtKey internalPrivateKey;
private int SIZE = -1;
private String cipherAlgorithm = "RSA/None/PKCS1PADDING";
private String keyAlgorithm = "RSA";
private int b64State = Base64.NO_WRAP;
private static int b64State_static = Base64.NO_WRAP;
public RSA(int size)
{
SIZE = size;
init();
}
public RSA(int size, RSAPublicKey puk, RSAPrivateCrtKey prk)
{
if(puk == null)
throw new RuntimeException("Err: PublicKey is null.");
if(prk != null)
{
if(!puk.getModulus().equals(prk.getModulus()))
throw new RuntimeException("Err: PublicKey not matched by PrivateKey.");
}
SIZE = size;
internalPublicKey = puk;
internalPrivateKey = prk;
}
private void init()
{
try
{
//SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm);
kpg.initialize(SIZE); //initialize(SIZE, new SecureRandom());
KeyPair kp = kpg.genKeyPair();
internalPublicKey = (RSAPublicKey) kp.getPublic();
internalPrivateKey = (RSAPrivateCrtKey) kp.getPrivate();
}
catch(Exception e)
{throw new RuntimeException("Err: init RSA. " + e.toString());}
}
public int getSize()
{
return SIZE;
}
public RSAPublicKey getPublicKey()
{
return internalPublicKey;
}
public RSAPrivateCrtKey getPrivateKey()
{
return internalPrivateKey;
}
public String getPublicModule()
{
String s = internalPublicKey.toString();
return s.substring(s.indexOf("modulus")+8, s.indexOf(",publicExponent"));
}
public BigInteger getPublicModuleInt()
{
return internalPublicKey.getModulus();
}
public String getPublicExponent()
{
String s = internalPublicKey.toString();
return s.substring(s.indexOf("publicExponent")+15, s.lastIndexOf("}"));
}
public BigInteger getPublicExponentInt()
{
return internalPublicKey.getPublicExponent();
}
public String getPrivateExponent()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("privateExponent")+16, s.indexOf(",primeP"));
}
public String getPrimP()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeP=")+7, s.indexOf(",primeQ"));
}
public String getPrimQ()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeQ=")+7, s.indexOf(",primeExponentP"));
}
public String getPrimExponentP()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeExponentP=")+15, s.indexOf(",primeExponentQ"));
}
public String getPrimExponentQ()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("primeExponentQ=")+15, s.indexOf(",crtCoefficient"));
}
public String getCrtCoefficient()
{
String s = internalPrivateKey.toString();
return s.substring(s.indexOf("crtCoefficient=")+15, s.lastIndexOf(","));
}
public byte[] getPublicKeyAsByte()
{
return internalPublicKey.getEncoded();
}
public byte[] getPrivateKeyAsByte()
{
return internalPrivateKey.getEncoded();
}
public void changeCipherAlgorithm(String algorithm)
{
cipherAlgorithm = algorithm;
}
public byte[] getEncrypt(byte[] plain)
{
try
{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, internalPublicKey);
return cipher.doFinal(plain);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(byte[] plain), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getEncrypt(String plain)
{
try
{
return getEncrypt(plain.getBytes("UTF-8"));
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getEncryptToB64(byte[] plain)
{
return Base64.encodeToString(getEncrypt(plain), b64State);
}
public byte[] getLargeEncrypt(byte[] plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = byPadding ? (getSize()/8) -11: (getSize()/8);
int offset = 0;
while(offset < plain.length)
{
byte[] section = Arrays.copyOfRange(plain, offset, Math.min(offset+n, plain.length));
byte[] cache = getEncrypt(section);
out.write(cache, 0, cache.length);
offset += n;
}
return out.toByteArray();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeEncrypt(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getLargeEncrypt(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
return getLargeEncrypt(plain.getBytes(Charset.forName("UTF-8")), byPadding);
}
public String getLargeEncryptToB64(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
return Base64.encodeToString(getLargeEncrypt(plain, byPadding), Base64.NO_WRAP);
}
public String getLargeEncryptToB64Block(String plain, boolean byPadding) //byPadding = true if use RSA/xxx/xxxPADDING
{
StringBuilder sb = new StringBuilder();
try
{
byte[] enc = plain.getBytes("UTF-8");
int n = byPadding ? (getSize()/8) -11: (getSize()/8);
int offset = 0;
while(offset < enc.length)
{
byte[] section = Arrays.copyOfRange(enc, offset, Math.min(offset+n, enc.length));
sb.append(getEncryptToB64(section));
offset += n;
}
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeEncryptToB64Block(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return sb.toString();
}
public String getLargeDecryptFromB64Block(String enc)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = (getSize()/8)-11;
int x = getEncryptToB64(TextHelper.generateString(n).getBytes("UTF-8")).length();
String[] ex = TextHelper.splitFix(enc, x);
for(int i=0; i<ex.length; i++)
{
byte[] sec = Base64.decode(ex[i], Base64.NO_WRAP);
out.write(sec, 0, sec.length);
//sb.append(getDecryptFromB64(ex[i]));
}
return getLargeDecryptToString(out.toByteArray());//sb.toString()
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeDecryptFromB64Block(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public byte[] getLargeDecrypt(byte[] enc)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
int n = (getSize()/8);
int offset = 0;
while(offset < enc.length)
{
byte[] section = Arrays.copyOfRange(enc, offset, Math.min(offset+n, enc.length));
byte[] cache = getDecrypt(section);
out.write(cache, 0, cache.length);
offset += n;
}
return out.toByteArray();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getLargeDecrypt(byte[] x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getLargeDecryptToString(byte[] enc)
{
return new String(getLargeDecrypt(enc), Charset.forName("UTF-8"));
}
public String getLargeDecryptFromB64(String encB64)
{
return getLargeDecryptToString(Base64.decode(encB64, Base64.NO_WRAP));
}
public byte[] getDecrypt(byte[] encryptedBytes)
{
try
{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, internalPrivateKey);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getDecrypt(byte[] x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getDecryptFromB64(String encrypted)
{
try
{
byte[] b = Base64.decode(encrypted.getBytes("UTF-8"), b64State);
return getDecryptAsString(b);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getDecryptFromB64(String x), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public String getDecryptAsString(byte[] encryptedBytes)
{
return new String(getDecrypt(encryptedBytes), Charset.forName("UTF-8"));
}
public static byte[] getEncrypt(byte[] plain, PublicKey pk, Cipher cipher)
{
try
{
cipher.init(Cipher.ENCRYPT_MODE, pk);
return cipher.doFinal(plain);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(byte[] x, PublicKey pk, Cipher cipher), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] getEncrypt(String plain, PublicKey pk, Cipher cipher)
{
try
{
return getEncrypt(plain.getBytes("UTF-8"), pk, cipher);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(String x, PublicKey pk, Cipher cipher), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] getDecrypt(byte[] encryptedBytes, PrivateKey pk, Cipher cipher)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, pk);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String getDecryptAsString(byte[] encryptedBytes, PrivateKey pk, Cipher cipher)
{
try
{
return new String(getDecrypt(encryptedBytes, pk, cipher), "UTF-8");
}
catch(Exception e){}
return null;
}
public static byte[] getDecrypt(final byte[] encryptedBytes, byte[] privateKey, Cipher cipher)
{
try
{
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
PrivateKey pk = keyFac.generatePrivate(keySpec);
cipher.init(Cipher.DECRYPT_MODE, pk);
return cipher.doFinal(encryptedBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String getDecryptAsString(final byte[] encryptedBytes, byte[] privateKey, Cipher cipher)
{
return new String(getDecrypt(encryptedBytes, privateKey, cipher), Charset.forName("UTF-8"));
}
public static byte[] sign(byte[] forSign, PrivateKey byThisKey)
{
try
{
Signature privateSignature = Signature.getInstance("SHA1withRSA");//or SHA256withRSA
privateSignature.initSign(byThisKey);
privateSignature.update(forSign);
return privateSignature.sign();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: sign(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String sign(String forSign, PrivateKey byThisKey)
{
return Base64.encodeToString(sign(forSign.getBytes(), byThisKey), b64State_static);
}
public static boolean verify(String plainText, String signature, PublicKey publicKey)
{
Signature publicSignature;
try
{
publicSignature = Signature.getInstance("SHA1withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes());
byte[] signatureBytes = Base64.decode(signature, b64State_static);
return publicSignature.verify(signatureBytes);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: verify(), ", Constants.DEFAULT_ALERT_STATE);
}
return false;
}
public static RSAPublicKey generatePublicKey(String modulus, String exponent)
{
try
{
BigInteger modBigInteger = new BigInteger(modulus, 16);
BigInteger exBigInteger = new BigInteger(exponent, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPublicKey) factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPublicKey generatePublicKey(BigInteger modulus, BigInteger exponent)
{
try
{
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPublicKey) factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPublicKey generatePublicKeyFromDotNet(String modulus, String exponent)
{
return generatePublicKey(RSA.parseDotNetBigInt(modulus), RSA.parseDotNetBigInt(exponent));
}
public static RSAPrivateCrtKey generatePrivateKeyFromDotNet(String modulus, String pubEx, String priEx, String p, String q, String dp, String dq,String invQ)
{
return generatePrivateKey(RSA.parseDotNetBigInt(modulus), RSA.parseDotNetBigInt(pubEx), RSA.parseDotNetBigInt(priEx), RSA.parseDotNetBigInt(p)
,RSA.parseDotNetBigInt(q),RSA.parseDotNetBigInt(dp), RSA.parseDotNetBigInt(dq), RSA.parseDotNetBigInt(invQ));
}
public static PublicKey generateBCPublicKey(String modulus, String exponent)
{
try
{
BigInteger modBigInteger = new BigInteger(modulus, 16);
BigInteger exBigInteger = new BigInteger(exponent, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
return factory.generatePublic(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getBCPublicKey(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey generatePrivateKey(String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
try
{
BigInteger module = new BigInteger(modulus, 16);
BigInteger expo1 = new BigInteger(publicExpo, 16);
BigInteger expo2 = new BigInteger(privateExpo, 16);
BigInteger prim_P = new BigInteger(primP, 16);
BigInteger prim_Q = new BigInteger(primQ, 16);
BigInteger prim_EP = new BigInteger(ePrimP, 16);
BigInteger prim_EQ = new BigInteger(ePrimQ, 16);
BigInteger coefficient = new BigInteger(cof, 16);
/*BigInteger module = new BigInteger(1, Base64.encode(modulus.getBytes(), b64State));*/
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(module, expo1, expo2, prim_P, prim_Q, prim_EP, prim_EQ, coefficient);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateCrtKey) factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey generatePrivateKey(BigInteger modulus, BigInteger publicExpo, BigInteger privateExpo, BigInteger primP, BigInteger primQ, BigInteger ePrimP, BigInteger ePrimQ, BigInteger cof)
{
try
{
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExpo, privateExpo, primP, primQ, ePrimP, ePrimQ, cof);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateCrtKey) factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static PrivateKey generateBCPrivateKey(String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
try
{
BigInteger module = new BigInteger(modulus, 16);
BigInteger expo1 = new BigInteger(publicExpo, 16);
BigInteger expo2 = new BigInteger(privateExpo, 16);
BigInteger prim_P = new BigInteger(primP, 16);
BigInteger prim_Q = new BigInteger(primQ, 16);
BigInteger prim_EP = new BigInteger(ePrimP, 16);
BigInteger prim_EQ = new BigInteger(ePrimQ, 16);
BigInteger coefficient = new BigInteger(cof, 16);
RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(module, expo1, expo2, prim_P, prim_Q, prim_EP, prim_EQ, coefficient);
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
return factory.generatePrivate(spec);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static Cipher generateCipher(String alg,#Nullable String provider)
{
try
{
if(provider == null)
return Cipher.getInstance(alg);
else
return Cipher.getInstance(alg, provider);
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: generateCipher(), ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static BigInteger parseDotNetBigInt(String b64BigInt)
{
try
{
String modulusHex = Hex.encodeHex(Base64.decode(b64BigInt.getBytes("UTF-8"), Base64.NO_WRAP));
return new BigInteger(modulusHex, 16);
}
catch (Exception ex)
{
ThreadHelper.exceptionAlert(ex, Constants.TAG_FOR_LOG, "Err: parseDotNetBigInt(),", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String privateKeyToXMLString(RSAPrivateCrtKey key)
{
try
{
Document xml = privateKeyToXML(key);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(sw));
return sw.getBuffer().toString();
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: privateKeyToXMLString(RSAPrivateCrtKey x),", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static String publicKeyToXMLString(RSAPublicKey key)
{
try
{
Document xml = publicKeyToXML(key);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(sw));
return sw.getBuffer().toString();
}
catch(Exception e){}
return null;
}
public static Document publicKeyToXML(RSAPublicKey key)
{
try
{
Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rsaKeyValue = result.createElement("RSAKeyValue");
result.appendChild(rsaKeyValue);
Element modulus = result.createElement("Modulus");
rsaKeyValue.appendChild(modulus);
byte[] modulusBytes = key.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);
modulus.appendChild(result.createTextNode(new String(Base64.encode(modulusBytes, b64State_static))));
Element exponent = result.createElement("Exponent");
rsaKeyValue.appendChild(exponent);
byte[] exponentBytes = key.getPublicExponent().toByteArray();
exponent.appendChild(result.createTextNode(new String(Base64.encode(exponentBytes, b64State_static))));
return result;
}
catch(Exception e){}
return null;
}
public static Document privateKeyToXML(RSAPrivateCrtKey key)
{
try
{
Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rsaKeyValue = result.createElement("RSAKeyValue");
result.appendChild(rsaKeyValue);
Element modulus = result.createElement("Modulus");
rsaKeyValue.appendChild(modulus);
Element exponent = result.createElement("Exponent");
rsaKeyValue.appendChild(exponent);
Element P = result.createElement("P");
rsaKeyValue.appendChild(P);
Element Q = result.createElement("Q");
rsaKeyValue.appendChild(Q);
Element DP = result.createElement("DP");
rsaKeyValue.appendChild(DP);
Element DQ = result.createElement("DQ");
rsaKeyValue.appendChild(DQ);
Element InverseQ = result.createElement("InverseQ");
rsaKeyValue.appendChild(InverseQ);
Element D = result.createElement("D");
rsaKeyValue.appendChild(D);
byte[] modulusBytes = key.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);
modulus.appendChild(result.createTextNode(new String(Base64.encode(modulusBytes, b64State_static))));
byte[] pubExponent = key.getPublicExponent().toByteArray();
exponent.appendChild(result.createTextNode(new String(Base64.encode(pubExponent, b64State_static))));
byte[] p = key.getPrimeP().toByteArray();
P.appendChild(result.createTextNode(new String(Base64.encode(p, b64State_static))));
byte[] q = key.getPrimeQ().toByteArray();
Q.appendChild(result.createTextNode(new String(Base64.encode(q, b64State_static))));
byte[] ep = key.getPrimeExponentP().toByteArray();
DP.appendChild(result.createTextNode(new String(Base64.encode(ep, b64State_static))));
byte[] eq = key.getPrimeExponentP().toByteArray();
DQ.appendChild(result.createTextNode(new String(Base64.encode(eq, b64State_static))));
byte[] cof = key.getCrtCoefficient().toByteArray();
InverseQ.appendChild(result.createTextNode(new String(Base64.encode(cof, b64State_static))));
byte[] priExponent = key.getPrivateExponent().toByteArray();
D.appendChild(result.createTextNode(new String(Base64.encode(priExponent, b64State_static))));
return result;
}
catch(Exception e)
{
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static byte[] stripLeadingZeros(byte[] input)
{
while (input[0] == (byte) 0)
{
input = Arrays.copyOfRange(input, 1, input.length);
}
return input;
}
public static void saveKey(File file, PublicKey key)
{
try
{
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key.getEncoded());
FileOutputStream fos = new FileOutputStream(file);
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
}
catch(Exception e){}
}
public static void saveKey(File file, PrivateKey key)
{
try
{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
FileOutputStream fos = new FileOutputStream(file);
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
catch(Exception e){}
}
public PublicKey openPublicKey(String path, String algorithm)
{
try
{
File filePublicKey = new File(path);
FileInputStream fis = new FileInputStream(path);
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
return keyFactory.generatePublic(publicKeySpec);
}
catch(Exception e){}
return null;
}
public PrivateKey openPrivateKey(String path, String algorithm)
{
try
{
File filePrivateKey = new File(path);
FileInputStream fis = new FileInputStream(path);
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);//RSA
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
return keyFactory.generatePrivate(privateKeySpec);
}
catch(Exception e){}
return null;
}
public static RSAPublicKey fetchPublicKeyFromXML(Document xml)
{
try
{
Element root = XMLMaster.getRoot(xml);
String mud = XMLMaster.getTextContent(root, "Modulus", 0);
String pubE = XMLMaster.getNodeValue(root, "Exponent", 0);
return generatePublicKeyFromDotNet(mud, pubE);
}
catch (Throwable e)
{
//throw new RuntimeException("Err: can not fetch PublicKey. " + e.toString());
ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: can not fetch PublicKey. ", Constants.DEFAULT_ALERT_STATE);
}
return null;
}
public static RSAPrivateCrtKey fetchPrivateKeyFromXML(Document xml)
{
try
{
Element root = XMLMaster.getRoot(xml);
String mud = XMLMaster.getTextContent(root, "Modulus", 0);
String pubE = XMLMaster.getNodeValue(root, "Exponent", 0);
String priE = XMLMaster.getNodeValue(root, "D", 0);
String p = XMLMaster.getNodeValue(root, "P", 0);
String Q = XMLMaster.getNodeValue(root, "Q", 0);
String EP = XMLMaster.getNodeValue(root, "DP", 0);
String EQ = XMLMaster.getNodeValue(root, "DQ", 0);
String cof = XMLMaster.getNodeValue(root, "InverseQ", 0);
return generatePrivateKeyFromDotNet(mud, pubE, priE, p, Q, EP, EQ, cof);
}
catch (Throwable e)
{
throw new RuntimeException("Err: can not fetch PrivateKey. " + e.toString());
}
}
public static PrivateKey loadPrivateKey(String privateKeyB64)
{
try
{
byte[] buffer = Base64.decode(privateKeyB64, Base64.NO_WRAP);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
//Class c = Reflector.getClassByAddressName("com.android.org.conscrypt.OpenSSLRSAPrivateKey");
//RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modules, d);
}
catch (Throwable e)
{
throw new RuntimeException("Err: can not load PrivateKey. " + e.toString());
}
}
public String convertCaseToString(BigInteger num)
{
return num.toString(16);
} // Use: convertCaseToString(rsa.getPublicModule())
}

Because you are working with encrypted data, it is unlikely you can convert that directly to a String (each byte may not correspond to a character store-able in a String) - therefore I'd expect bytesToString(encryptedBytes) to usually fail. Try converting the encrypted data to Base64 first then that will always be store-able in a String. You then simply do the reverse to decrypt:-
// to encrypt and get a String object
byte[] encode = Base64.encode(encryptedBytes, Base64.NO_PADDING|Base64.NO_WRAP);
String encryptedDataStr = new String(encode);
Then you can do stuff (like store) the encryptedDataStr or whaterver. Then later...
// to decrypt
byte[] encryptedBytes = Base64.decode(encryptedDataStr, Base64.NO_PADDING|Base64.NO_WRAP);
byte [] decryptedBytes = cipher1.doFinal(encryptedBytes);
Good luck!

Related

AES with salt from java to PHP get different result

I had issue when converting AES encryption from java to php, it show different value result in php, that should show the exact value from java
Java
public class AesUtil {
private final Cipher cipher;
public final static String passPhrase = "";
public final static String IV = ""; //32bit IV Lenght
public final static String SALT = "";
public final static int KEY_SIZE = 128;
public final static int ITERATION_COUNT = 10000;
public AesUtil() {
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw fail(e);
}
}
//Call this function to encrypt some String
public String encrypt(String passPhrase, String plaintext) {
try {
SecretKey key = generateKey(SALT, passPhrase);
byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, IV, plaintext.getBytes("UTF-8"));
return base64(encrypted);
}
catch (UnsupportedEncodingException e) {
throw fail(e);
}
}
private byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
try {
cipher.init(encryptMode, key, new IvParameterSpec(hex(IV)));
return cipher.doFinal(bytes);
}
catch (InvalidKeyException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException
| BadPaddingException e) {
throw fail(e);
}
}
private SecretKey generateKey(String salt, String passphrase) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), ITERATION_COUNT, KEY_SIZE);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return key;
}
catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw fail(e);
}
}
public static String random(int length) {
byte[] salt = new byte[length];
new SecureRandom().nextBytes(salt);
return hex(salt);
}
public static String base64(byte[] bytes) {
return new String(Base64.encodeBase64(bytes));
}
public static byte[] base64(String str) {
return Base64.decodeBase64(str.getBytes());
}
public static String hex(byte[] bytes) {
return Hex.encodeHexString(bytes);
}
public static byte[] hex(String str) {
try {
return Hex.decodeHex(str.toCharArray());
}
catch (DecoderException e) {
throw new IllegalStateException(e);
}
}
private IllegalStateException fail(Exception e) {
return new IllegalStateException(e);
}
}
this is my code in php version,
<?php
$password = "";
$salt = "";
$iv = ""; //32bit IV Lenght
$length = 16;
$salt = "";
$interation = 10000;
$key1 = mb_convert_encoding($password, "UTF-8");
$bytes = openssl_pbkdf2($key1, $salt, $length, $interation, "sha1");
$bytes2 = hash_pbkdf2("sha1", $password, $salt, $interation, $length, true);
$ciphertext_b64 = base64_encode(openssl_encrypt($plaintext,"aes-128-cbc", $bytes2,OPENSSL_RAW_DATA, $iv));
?>
Please tell me how to solve this problem, if you have any suggestion in different programming language it's no problem, thank you

Error trying to verify signature on CBOR message

I'm having problems decoding EU Digital Certificate ("Covid pass") using COSE-JAVA. Public key appears to load ok but when I try to validate the CBOR message, I get following error:
COSE.CoseException: Signature verification failure
at COSE.SignCommon.validateSignature(SignCommon.java:205)
at COSE.Signer.validate(Signer.java:212)
at COSE.Message.validate(Message.java:288)
Caused by: java.lang.NullPointerException: Attempt to get length of null array
at COSE.SignCommon.convertConcatToDer(SignCommon.java:212)
Here is code for validation:
public static String DecodeMessage(byte[] data) throws CoseException, CborParseException {
Message m = Encrypt0Message.DecodeFromBytes(data);
PublicKey key = getPublicKey("here goes PEM of public key");
CborMap cborMap = CborMap.createFromCborByteArray(m.GetContent());
CounterSign signer = new CounterSign();
signer.setKey(new OneKey(key, null));
signer.addAttribute(HeaderKeys.Algorithm, AlgorithmID.ECDSA_256.AsCBOR(), Attribute.ProtectedAttributes);
// error happens here
m.validate(signer);
return cborMap.toJsonString();
}
This is how public key is generated from PEM:
public static PublicKey getPublicKey(String keyData) {
try
{
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
Reader rdr = new StringReader(
"-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
);
org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
byte[] content = spki.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
}
catch (Exception ex)
{
return null;
}
Public key is defined as:
"publicKeyAlgorithm": {
"hash": {
"name": "SHA-256"
},
"name": "ECDSA",
"namedCurve": "P-256"
},
"publicKeyPem": "..."
Here is code for doing same thing in Python, might help someone. Code must work on Android 7.1 (embedded device, no way to upgrade to newer Android).
Solved...
public static boolean VerifySignature(byte[] data, String publicKey) {
boolean result = false;
try {
Message m = Encrypt0Message.DecodeFromBytes(data);
Sign1Message sm = (Sign1Message) m;
PublicKey key = getPublicKey(publicKey);
if (sm.validate(new OneKey(key, null))) {
result = true;
}
} catch (Exception ex) {
log.error("Error verifying signature", ex);
}
return result;
}
and
public static PublicKey getPublicKey(String keyData) {
try {
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
Reader rdr = new StringReader(
"-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
);
org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
byte[] content = spki.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
} catch (Exception ex) {
return null;
}
}
ODqaG8mnbro=": {
"serialNumber": "5dfefffd3a560d58",
"subject": "C=BE, O=eHealth - Belgium, CN=Belgium Covid19 DSC 01",
"issuer": "C=BE, O=eHealth - Belgium, CN=Belgium Covid19 Country Signing CA 01",
"notBefore": "2021-05-27T10:12:47.000Z",
"notAfter": "2023-05-27T10:12:47.000Z",
"signatureAlgorithm": "ECDSA",
"fingerprint": "2942d10907cf19f27aeb0dc391f35197c69dea87",
"publicKeyAlgorithm": {
"hash": {
"name": "SHA-256"
},
"name": "ECDSA",
"namedCurve": "P-256"
},
"publicKeyPem": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEU/f/KsmP3NasU/jZo7aulTrd9GHoznfnwWvX8xmHtK49EoobMAG7LhXnpLQ+aRwmmnSMcIWy8wPxM8QDMBUtyA=="
}

AES Crypto C# compatible Java

I have this code in C # which generates an encrypted password.
I would like to make it compatible in Java.
Code C#
private static string ccs = "&Ux#B*******";
private static ICryptoTransform __Get_AES128_Transform(string password, bool AsDecryptor)
{
const int KEY_SIZE = 16;
var sha256CryptoServiceProvider = new SHA256CryptoServiceProvider();
var hash = sha256CryptoServiceProvider.ComputeHash(Encoding.Unicode.GetBytes(password));
var key = new byte[KEY_SIZE];
var iv = new byte[KEY_SIZE];
Buffer.BlockCopy(hash, 0, key, 0, KEY_SIZE);
if (AsDecryptor)
return new AesCryptoServiceProvider().CreateDecryptor(key, iv);
else
return new AesCryptoServiceProvider().CreateEncryptor(key, iv);
}
public static string Encrypt(this string Value)
{
byte[] Buffer = Encoding.Unicode.GetBytes(Value);
using (ICryptoTransform transform = __Get_AES128_Transform(ccs, false))
{
byte[] encyptedBlob = transform.TransformFinalBlock(Buffer, 0, Buffer.Length);
return Convert.ToBase64String(encyptedBlob);
}
}
Could anyone give a direction to decrypt in java?
My answer interoperable encrypt, I hope this helps you. Result can be decrypted from any platform - C# code or Android/Java code.
Encrypt from C# -> Decrypt from C#, Android, Java.
Encrypt from Android -> Decrypt from Android, Java, C#.
Encrypt from Java -> Decrypt from Java, Android, C#.
The result of encrypt contains the encrypted text + IV.
IV is generated using secure random algoritm.
Encrypt process
Transform plaintext => plaintextBytes
Transform password => passwordBytes => Sha256(passwordbytes) = passwordHashBytes
generate random IV bytes = ivBytes
encrypt using plaintextbytes and passwordHashBytes
join (encryptedbytes + ivBytes)
Transform to base64 joined bytes.
Decrypt process
Transform base64 string to bytes.
Split array encryptedBytes, ivBytes
Transform password => passwordBytes => Sha256(passwordbytes) = passwordHashBytes
Decrypt using ivBytes, EncryptedBytes, PasswordHashBytes
Transform DecryptedBytes to String
The IV is randomized in every Encrypt process to get different output with same text and avoid to intruders/attackers get original text easily.
The default mode is CBC.
The encoding used is UTF-8. UTF-8 is the most widely used encoding on the web. Check Usage of character encodings broken down by ranking
References
Initialization vector
Block cipher mode of operation
C# Implementation
using System;
using System.Security.Cryptography;
using System.Text;
public enum HashAlgorithm
{
MD5,
SHA1,
SHA256,
SHA384,
SHA512
}
public class HashManager
{
public static byte[] ToRawHash(byte[] data, HashAlgorithm algorithm)
{
byte[] hash;
switch (algorithm)
{
case HashAlgorithm.MD5:
MD5 md5 = MD5.Create();
hash = md5.ComputeHash(data, 0, data.Length);
return hash;
case HashAlgorithm.SHA1:
SHA1Managed sha1 = new SHA1Managed();
hash = sha1.ComputeHash(data);
return hash;
case HashAlgorithm.SHA256:
SHA256Managed sha256 = new SHA256Managed();
hash = sha256.ComputeHash(data);
return hash;
case HashAlgorithm.SHA384:
SHA384Managed sha384 = new SHA384Managed();
hash = sha384.ComputeHash(data);
return hash;
case HashAlgorithm.SHA512:
SHA512Managed sha512 = new SHA512Managed();
hash = sha512.ComputeHash(data, 0, data.Length);
return hash;
default:
throw new ArgumentException("Invalid Algorithm");
}
}
}
public class AesManager
{
private const int MAX_IV_LENGTH = 16;
private const int MAX_KEY_LENGTH = 32;
private static byte[] GenerateValidKey(byte[] keyBytes)
{
byte[] ret = new byte[MAX_KEY_LENGTH];
byte[] hash = HashManager.ToRawHash(keyBytes, HashAlgorithm.SHA256);
Array.Copy(hash, ret, MAX_KEY_LENGTH);
return ret;
}
public static byte[] EncryptRaw(byte[] PlainBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
AesAlgorithm.GenerateIV();
var Encrypted = AesAlgorithm.CreateEncryptor().TransformFinalBlock(PlainBytes, 0, PlainBytes.Length);
byte[] ret = new byte[Encrypted.Length + MAX_IV_LENGTH];
Array.Copy(Encrypted, ret, Encrypted.Length);
Array.Copy(AesAlgorithm.IV, 0, ret, ret.Length - MAX_IV_LENGTH, MAX_IV_LENGTH);
return ret;
}
public static byte[] DecryptRaw(byte[] CipherBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
byte[] IV = new byte[MAX_IV_LENGTH];
Array.Copy(CipherBytes, CipherBytes.Length - MAX_IV_LENGTH, IV, 0, MAX_IV_LENGTH);
AesAlgorithm.IV = IV;
byte[] RealBytes = new byte[CipherBytes.Length - MAX_IV_LENGTH];
Array.Copy(CipherBytes, RealBytes, CipherBytes.Length - MAX_IV_LENGTH);
return AesAlgorithm.CreateDecryptor().TransformFinalBlock(RealBytes, 0, RealBytes.Length); ;
}
public static String EncryptToBase64(String Plaintext, String Key)
{
byte[] PlainBytes = Encoding.UTF8.GetBytes(Plaintext);
return Base64Manager.ToBase64(EncryptRaw(PlainBytes, Encoding.UTF8.GetBytes(Key)), false);
}
public static String DecryptFromBase64(String CipherText, String Key)
{
byte[] CiPherBytes = Base64Manager.Base64ToByteArray(CipherText);
byte[] Encrypted = DecryptRaw(CiPherBytes, Encoding.UTF8.GetBytes(Key));
return Encoding.UTF8.GetString(Encrypted, 0, Encrypted.Length);
}
}
public class Base64Manager
{
public static byte[] Base64ToByteArray(String base64)
{
return Convert.FromBase64String(base64);
}
public static String ToBase64(byte[] data, Boolean insertLineBreaks = default(Boolean))
{
return insertLineBreaks ? Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks) : Convert.ToBase64String(data);
}
}
public class Program
{
public static void Main()
{
string plainText = "plain text";
string password = "password";
string encrypted = AesManager.EncryptToBase64(plainText, password);
Console.WriteLine(encrypted);
Console.WriteLine(AesManager.DecryptFromBase64(encrypted, password));
Console.ReadLine();
}
}
Android/Java Implementation
public enum HashAlgorithm {
SHA512("SHA-512"),
SHA256("SHA-256"),
SHA384("SHA-384"),
SHA1("SHA-1"),
MD5("MD5");
private String Value = "";
HashAlgorithm(String Value) {
this.Value = Value;
}
#Override
public String toString() {
return Value;
}
}
import java.security.MessageDigest;
public class HashManager {
public static byte[] toRawHash(byte[] data,
HashAlgorithm algorithm) throws Exception
{
byte[] buffer = data;
MessageDigest messageDigest = MessageDigest.getInstance(algorithm.toString());
messageDigest.reset();
messageDigest.update(buffer);
return messageDigest.digest();
}
}
Base64Manager class Android implementation
import android.util.Base64;
public class Base64Manager {
public static String toBase64(byte[] data,
boolean insertLineBreaks) throws Exception
{
String ret;
if (insertLineBreaks)
{
ret = Base64.encodeToString(data, Base64.DEFAULT);
}
else
{
ret = Base64.encodeToString(data, Base64.NO_WRAP);
}
return ret;
}
public static String toBase64(String data,
boolean insertLineBreaks) throws Exception
{
return toBase64(data.getBytes("UTF-8"), insertLineBreaks);
}
public static byte[] base64ToByteArray(String base64) throws Exception
{
return base64.contains(System.getProperty("line.separator")) ? Base64.decode(base64, Base64.DEFAULT) : Base64.decode(base64, Base64.NO_WRAP);
}
}
Base64Manager class Java8+ implementation
import java.util.Base64;
public class Base64Manager {
public static String toBase64(byte[] data, Boolean insertLineBreaks) throws Exception {
String ret;
if (insertLineBreaks) {
ret = Base64.getMimeEncoder().encodeToString(data);
} else {
ret = Base64.getEncoder().encodeToString(data);
}
return ret;
}
public static String toBase64(String data, Boolean insertLineBreaks) throws Exception {
return toBase64(data.getBytes("UTF-8" ), insertLineBreaks);
}
public static byte[] base64ToByteArray(String base64) throws Exception {
return base64.contains(System.getProperty("line.separator")) ? Base64.getMimeDecoder().decode(base64) : Base64.getDecoder().decode(base64);
}
}
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesManager {
private static final int MAX_IV_LENGTH = 16;
private static final int MAX_KEY_LENGTH = 32;
public static String decryptFromBase64(String cipherText, String key) throws Exception {
byte[] CiPherBytes = Base64Manager.base64ToByteArray(cipherText);
byte[] KeyBytes = key.getBytes("UTF-8");
return new String((decryptRaw(CiPherBytes, KeyBytes)));
}
public static byte[] generateValidKey(byte[] key) throws Exception {
return Arrays.copyOf(HashManager.toRawHash(key, HashAlgorithm.SHA256), MAX_KEY_LENGTH);
}
public static byte[] decryptRaw(byte[] cipherBytes, byte[] keyBytes) throws Exception {
byte[] IV = Arrays.copyOfRange(cipherBytes, cipherBytes.length - MAX_IV_LENGTH, cipherBytes.length);
byte[] RealBytes = Arrays.copyOf(cipherBytes, cipherBytes.length - MAX_IV_LENGTH);
Cipher AesAlgorithm = Cipher.getInstance("AES/CBC/PKCS5Padding" );
byte[] ValidKeyBytes = generateValidKey(keyBytes);
SecretKeySpec secretKeySpec = new SecretKeySpec(ValidKeyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV);
AesAlgorithm.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] Decrypted = AesAlgorithm.doFinal(RealBytes);
return Decrypted;
}
public static byte[] encryptRaw(byte[] plainBytes, byte[] keyBytes) throws Exception {
Cipher AesAlgorithm = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ValidKeyBytes = generateValidKey(keyBytes);
SecretKeySpec secretKeySpec = new SecretKeySpec(ValidKeyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(generateIV());
AesAlgorithm.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] Encrypted = AesAlgorithm.doFinal(plainBytes);
byte[] ret = new byte[Encrypted.length + MAX_IV_LENGTH];
System.arraycopy(Encrypted, 0, ret, 0, Encrypted.length);
System.arraycopy(ivParameterSpec.getIV(), 0, ret, Encrypted.length, MAX_IV_LENGTH);
return ret;
}
private static byte[] generateIV() throws Exception {
return generateRandomArray(MAX_IV_LENGTH);
}
public static byte[] generateRandomArray(int size) {
SecureRandom RandomGenerator = new SecureRandom();
byte[] ret = new byte[size];
RandomGenerator.nextBytes(ret);
return ret;
}
public static String encryptToBase64(String plaintext, String key) throws Exception {
byte[] PlainBytes = plaintext.getBytes("UTF-8");
byte[] KeyBytes = key.getBytes("UTF-8");
return Base64Manager.toBase64(encryptRaw(PlainBytes, KeyBytes), false);
}
}
public class Program {
public static void main(String[] args) throws Exception
{
String plainText = "plain text";
String password = "password";
String encrypted = AesManager.encryptToBase64(plainText, password);
System.out.println(encrypted);
System.out.println(AesManager.decryptFromBase64(encrypted, password));
}
}
Output
Java
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
leHBoUoB54bd9JEa9s9INohjVjmb2RZqVzrz2uYEstg=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
wC6o7cUqZn9KS88L11OuNR2lGDcJ6zBrK1etJEpMHEg=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
gfM1uVf2a3x6Q/N0XhpDI4svUZx4kTmcl0wkjJfNQrw=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target>
Dotnet
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
4GTqXhjkh0tXNI6Q4hShSdPPrKcWVEqA5LRBn6fBCH8=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
aYY1sxre9KfLqkA1XtvN4IwGau6mYInmuvkopFXuKQA=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
7lesPYAHQxdiCN4Cv5yWyWJlf5pqIukznZzpZTOOFeg=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0>

Encrypt/Decrypt String using Public/Private Key in Java and Javascript

I am generating a public and private key pair in javascript. The public key is being sent to the server where I have java code that encrypts the string. When I try to decrypt the string in Javascript using a private key I get an error. Here is the Javascript code I used.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CryptographyService {
private publicKey: string;
private privateKey: string;
public randomKey: string;
private keyPair: CryptoKeyPair;
public exportedKey: string;
constructor() {
/**Generate the public and private key */
this.generateKeys()
.then(() => {
return this.exportKey(this.keyPair.publicKey);
})
.then(() => {});
}
public setPublicKey(key: string) {
this.publicKey = key;
}
public setRandomKey(key: string) {
this.randomKey = key;
}
public setPrivateKey(key: string) {
this.privateKey = key;
}
public async encryptMessage(text: String) {
const { default: NodeRSA } = await import('node-rsa');
const key = NodeRSA(this.publicKey, 'pkcs8-public');
return key.encrypt(text, 'base64');
}
// For subscription key encryption and decryption
private async generateKeys() {
const keyPair = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP', //algorithm
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
true,
['encrypt', 'decrypt']
);
this.keyPair = keyPair; /**{
publicKey:
privateKey:
} */
}
private async exportKey(key: CryptoKey) {
/** exportKey() it takes as input a CryptoKey object and gives you the key in an external, portable format.
* crypto.subtle.exportKey(format, key); : returns a promise
* spki format is used to import/export RSA or Elliptic Curve public keys.
*/
const exported = await crypto.subtle.exportKey('spki', key); //Returns an ArrayBuffer
const exportedAsString = this.ab2str(exported); // Converts ArrayBuffer to String
/**btoa encodes a string to base64 */
const exportedAsBase64 = window.btoa(exportedAsString);
this.exportedKey = exportedAsBase64;
}
// Uses private key to decrypt message sent from the backend
public async decryptMessage(input: string) {
const ciphertext = this.str2ab(input);
const decrypted = await window.crypto.subtle.decrypt(
{
name: 'RSA-OAEP'
},
this.keyPair.privateKey,
ciphertext
);
const dec = new TextDecoder();
const decodedMessage = dec.decode(decrypted);
return decodedMessage;
}
private ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
private str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
}
The java code to convert the string to PublicKey Object
String pubKey = loginRequest.publicKey;
PublicKey pk = null;
try {
byte[] keyBytes = Base64.decodeBase64(pubKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
pk = kf.generatePublic(spec);
} catch (Exception e) {
System.out.println("Exception in generating primary key: " + e.getMessage());
}
Encrypting the string with the publicKey
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key, oaepParams);
cipherText = cipher.doFinal(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
I get back an encrypted string when when I try to decode it in Javascript I get an error. Any idea what I need to change in my code to fix this?

DSA signature - java.security.SignatureException: invalid encoding for signature

I have problem with DSA signature. My DSA code:
public byte[] signing(String text, PrivateKey privatekey) throws Exception {
byte[] textByte = text.getBytes();
Signature sign = Signature.getInstance("DSA");
sign.initSign(privatekey);
sign.update(textByte);
return sign.sign();
}
public boolean verify(String text, byte[] signature, PublicKey publickey) throws Exception {
byte[] textByte = text.getBytes();
Signature sign = Signature.getInstance("DSA");
sign.initVerify(publickey);
sign.update(textByte);
return sign.verify(signature);
}
And I run it on button action:
private void jButton9ActionPerformed(java.awt.event.ActionEvent evt) {
String message = jTextArea1.getText();
try {
signed = dsa.signing(message, privKey);
} catch (Exception ex) {
Logger.getLogger(DSAFrame.class.getName()).log(Level.SEVERE, null, ex);
}
String signedString = new String(signed);
jTextArea2.setText(signedString);
}
private void jButton10ActionPerformed(java.awt.event.ActionEvent evt) {
String signedString = jTextArea1.getText();
signToVer = jTextArea2.getText().getBytes();
try {
boolean correct = dsa.verify(signedString, signToVer, pubKey);
if(correct == true) {
JOptionPane.showMessageDialog(this, "Podpis poprawny", "Sukces", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, "Podpis niepoprawny", "Błąd", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception ex) {
Logger.getLogger(DSAFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
When I want verify signature, it throw me an java.security.SignatureException: invalid encoding for signature. I think, it's a problem with conversion string to byte array and back. But I don't know how to make it work.

Categories