I am doing Encryption in C# for windows phone 8.1 app and I need to decrypt it using java.
Here is my Encryption code
public static String encrypt(String plaintext, KeyParameter keyParam)
{
byte[] ivData = new byte[AES_NIVBITS / 8];
Random r = new Random();
r.NextBytes(ivData);
IBlockCipherPadding padding = new Pkcs7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new AesEngine()), padding);
ICipherParameters param = new ParametersWithIV(keyParam, ivData);
cipher.Reset();
cipher.Init(true, param);
byte[] bytesDec = Encoding.GetEncoding("iso-8859-1").GetBytes(plaintext);
byte[] bytesEnc = null;
int buflen = cipher.GetOutputSize(bytesDec.Length);
System.Diagnostics.Debug.WriteLine("enc length " + buflen);
bytesEnc = new byte[buflen];
int nBytesEnc = cipher.ProcessBytes(bytesDec, 0, bytesDec.Length, bytesEnc, 0);
nBytesEnc += cipher.DoFinal(bytesEnc, nBytesEnc);
if (nBytesEnc != bytesEnc.Length)
{
throw new Exception("Unexpected behaviour : getOutputSize value incorrect");
}
byte[] bytesAll = new byte[ivData.Length + bytesEnc.Length];
Array.Copy(ivData, 0, bytesAll, 0, ivData.Length);
Array.Copy(bytesEnc, 0, bytesAll, ivData.Length, bytesEnc.Length);
byte[] bytesAllb64 = Base64.Encode(bytesAll);
return Encoding.GetEncoding("iso-8859-1").GetString(bytesAllb64, 0, bytesAllb64.Length);
}
And this is the java code for decryption
public static String decodeBase64Aes(String encodedciphertext, KeyParameter keyParam) throws Exception
{
byte[] bytesEnc = Base64.decode(encodedciphertext.getBytes(ISO8859));
int nIvBytes = AES_NIVBITS / 8;
byte[] ivBytes = new byte[nIvBytes];
System.arraycopy(bytesEnc, 0, ivBytes, 0, nIvBytes);
CipherParameters params = new ParametersWithIV(keyParam, ivBytes);
BlockCipherPadding padding = new PKCS7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), padding);
cipher.reset();
cipher.init(false, params);
byte[] bytesDec = null;
int buflen = cipher.getOutputSize(bytesEnc.length - nIvBytes);
byte[] workingBuffer = new byte[buflen];
int len = cipher.processBytes(bytesEnc, nIvBytes, bytesEnc.length - nIvBytes, workingBuffer, 0);
len += cipher.doFinal(workingBuffer, len);
bytesDec = new byte[len];
System.arraycopy(workingBuffer, 0, bytesDec, 0, len);
return new String(bytesDec, ISO8859);
}
When I am encrypting it it's working fine but when I test decryption using the encrypted text I got and key, it throws
Exception in thread "main" org.bouncycastle.crypto.DataLengthException: last block incomplete in decryption
I can only change the c# part. Any help would be highly appreciated???
Key -> 8fe3f8b34e87744c175aae43cc52ee13
'Hello World' -> Nb90n51LqK13LzpalV7qTs7YJqe9m+Ni9uA/U7tU06Y=
The Exception Comes on line
len += cipher.doFinal(workingBuffer, len);
When I encrypt "Hello World" from java using the same key from the encryption method I have on my server I get
uWMz8ZIPh+3jnGtwxpuyK9Qht7BJV4RQ/Iet9JeTrTk=
EDIT ------
Updated to working code.
Base 64 does not give same length as the original one and that's why I was gettting that error. I have updated the code with the correct one.
Related
I am new at flutter development, I am trying to use send ENCRYPTED data on server using a public key in flutter .
I have .cer certificate and i have RSA public key in flutter. Now in Java I'm using for Encrypt the Plain Text using RSA public key i have done this
successfully . How can i do this in flutter ?
public String encrypt(String string, final X509Certificate x509Certificate) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
Cipher a = Cipher.getInstance("RSA");
final KeyGenerator instance;
(instance = KeyGenerator.getInstance("AES")).init(256);
byte[] b = instance.generateKey().getEncoded();
System.out.println("print encoded key"+b);
printUnsignedBytes(b);
aesKey = b;
new SecretKeySpec(b, "AES");
a.init(1, x509Certificate.getPublicKey());
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final CipherOutputStream cipherOutputStream;
(cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, a)).write(b);
cipherOutputStream.close();
byte[] c = byteArrayOutputStream.toByteArray();
final byte[] array = new byte[16];
new SecureRandom().nextBytes(array);
final Cipher instance2;
(instance2 = Cipher.getInstance("AES/CBC/NOPADDING")).init(1, new SecretKeySpec(b, "AES"),
new IvParameterSpec(array));
byte[] bytes = s.getBytes();
int remainder = 16 - (bytes.length % 16);
byte[] remainderFilledWithSpaces = new byte[remainder];
for (int i = 0; i < remainderFilledWithSpaces.length; i++) {
remainderFilledWithSpaces[i] = " ".getBytes()[0];
}
int totalLength = bytes.length + remainder;
ByteBuffer bb = ByteBuffer.allocate(totalLength);
bb.put(bytes);
bb.put(remainderFilledWithSpaces);
bb.position(0);
byte[] blockToEncrypt = new byte[16];
ByteBuffer encrypted = ByteBuffer.allocate(totalLength);
while (bb.hasRemaining()) {
bb.get(blockToEncrypt);
byte[] update = instance2.update(blockToEncrypt);
encrypted.put(update);
}
instance2.doFinal();
final ByteArrayOutputStream byteArrayOutputStream2 = new ByteArrayOutputStream();
final byte[] array2;
(array2 = new byte[4])[0] = 0;
array2[1] = 1;
array2[3] = (array2[2] = 0);
byteArrayOutputStream2.write(array2, 0, 4);
array2[0] = 16;
array2[1] = 0;
array2[3] = (array2[2] = 0);
byteArrayOutputStream2.write(array2, 0, 4);
byteArrayOutputStream2.write(c, 0, 256);
byteArrayOutputStream2.write(array, 0, 16);
byteArrayOutputStream2.write(encrypted.array());
return s = new String(Base64.getMimeEncoder().encode(byteArrayOutputStream2.toByteArray()));
}
Now , I want this same solution in Dart .Please help,thanks a lot.
I want to encrypt decrypt using bouncycastle.
by code sometimes works and sometimes not.
For example for this code:
String msg="ivivivi;message";
String key="1234567891234567";
SecureRandom secureRandom = new SecureRandom();
byte[] keyB = new byte[16];
secureRandom.nextBytes(keyB);
String cipher=Encryption.encrypt(msg.getBytes(),key.getBytes(),keyB);
System.out.println("cipher: "+cipher);
String original=Encryption.decrypt(cipher.getBytes(), key.getBytes(), keyB);
System.out.println("original: "+original);
Expected output:
cipher: c÷cAn‘iµHy~‹eX03
original: ivivivi;message
This gives the output, but if run run the code again and again it sometimes gives the expected result and sometimes not.
when it is not work, it thorws error:
org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
Here my ecrypt/decrypt functions:
private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data)
throws Exception
{
byte[] result=null;
try{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
}catch(Exception e){
System.err.println("Encryption [0010] "+e.getMessage());
}
return result;
}
public static String decrypt(byte[] cipher, byte[] key, byte[] iv) throws Exception
{
System.out.println("Encryption decrypt: "+new String(cipher));
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
try {
aes.init(false, ivAndKey);
} catch (Exception e) {
return "";
}
byte[] cip=cipherData(aes, cipher);
if(cip==null){
System.err.println("Encryption.decrypt [0011]: cip is null");
return "";
}
String result=new String(cip);
System.out.println("Encryption decrypted: "+result);
return result;
}
public static String encrypt(byte[] plain, byte[] key, byte[] iv) throws Exception
{
System.out.println("Encryption encrypt: "+new String(plain));
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
return new String(cipherData(aes, plain));
}
what am I missing?
On server (PHP code), we have 2 methods to encrypt/decrypt facebook id like this:
private function encryptFacebookId($text)
{
$method = "AES-256-CBC";
$iv_size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = openssl_encrypt($text, $method, $this->_cryptKey, 0, $iv);
return base64_encode($iv . $encrypted);
}
public function decryptFacebookId($text)
{
$text = base64_decode($text);
$method = "AES-256-CBC";
$iv_size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CBC);
$iv = substr($text, 0, $iv_size);
$decrypted = openssl_decrypt(substr($text, $iv_size), $method, $this->_cryptKey, 0, $iv);
return $decrypted;
}
with _cryptKey="1231238912389123asdasdklasdkjasd";
It's OK with the same value of input and output at server. But When I'm connecting to server as client (Android/Java) by HTTP request (REST).
I try to convert method of PHP code to Java code at method "encryptFacebookId($text)" and send encryption text to server but the result of method decryptFacebookId($text) at server is not same value with the client.
This is my code at client
String facebookId = "123456789";
String keyCrypt = "1231238912389123asdasdklasdkjasd";
try {
SecretKeySpec skeySpec = new SecretKeySpec(keyCrypt.getBytes(),
"AES");
Cipher enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivData = new byte[enCipher.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivData);
enCipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encryptedBytes = enCipher.doFinal(facebookId.getBytes());
String ivEncrypted = new String(ivData)
+ new String(encryptedBytes);
String strEncode = Base64
.encodeBase64String(ivEncrypted.getBytes());
System.out.println(strEncode);
} catch (Exception e) {
System.out.println(e.getMessage());
}
Please help me to find the right way.
1) If you want to concat binary byte[] don't transform it to String use for example:
public static byte[] concat(byte[]... args)
{
int fulllength = 0;
for (byte[] arrItem : args) {
fulllength += arrItem.length;
}
byte[] outArray = new byte[fulllength];
int start = 0;
for (byte[] arrItem : args) {
System.arraycopy(arrItem, 0, outArray, start, arrItem.length);
start += arrItem.length;
}
return outArray;
}
byte[] ivEncrypted = concat(ivData, encryptedBytes);
2) You have to be sure that the Base64 encoders are compatible.
While trying to implement AES-GCM for the first time, we are facing issue in generating AuthenticationTag, Encrypted cipher & GCM mac check fails in the end. For out current implementation tag[] is being populated but byte[] encrypted remains empty. And because of this cipher.doFinal(data1, offset) gives 'mac check in GCM failed'. It appears to be some issue around the size of byte arrays, can someone please share on what basis should the output buffer size be determined? Should this be done in chunks?
Any pointers/links to AES-GCM implementation will be highly appreciated.
Following is our implementation:
public class GCMTest {
public static void main(String[] args) throws Exception {
//***********************************************************
//Key
byte[] key = MessageDigest.getInstance("MD5").digest("1234567890123456".getBytes("UTF-8"));//this is the random key
//Iv
SecureRandom srand = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[256];
srand.nextBytes(iv);
//Input
byte[] data="inputPlainText".getBytes();
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
//***********************************************************
//Encryption
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", new BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), gcmParameterSpec);
cipher.updateAAD("MyAAD".getBytes("UTF-8"));
//Encrypted output
final byte[] encrypted = new byte[cipher.getOutputSize(data.length)];
cipher.update(data, 0, data.length, encrypted, 0); //Not being updated for current data.
//Tag output
byte[] tag = new byte[cipher.getOutputSize(data.length)];
cipher.doFinal(tag, 0);
//***********************************************************
//Decryption
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
cipher.updateAAD("MyAAD".getBytes("UTF-8"));
//What size should be assigned to outputBuffer?
final byte[] data1 = new byte[256];
int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
cipher.update(tag, 0, tag.length, data1, offset);
cipher.doFinal(data1, offset);
boolean isValid = checkEquals(data, data1);
System.out.println("isValid :"+isValid);
}
private static boolean checkEquals(byte[] a, byte[] b)
{
int diff = a.length ^ b.length;
for(int i = 0; i < a.length && i < b.length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
}
It gives following exception:
Exception in thread "main" javax.crypto.AEADBadTagException: mac check in GCM failed
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2068)
at GCMTest.main(GCMTest.java:56)
Thanks in advance!!
I was having this same issue. For me, it had to do with encoding the string. I ended up doing:
Get ASCII bytes from string you want to encrypt (UTF-8 in your case)
Encrypt bytes
Encode bytes in Base64 string
Then to decrypt string I did:
Decode encrypted string to Base64 bytes
Decrypt Base64 bytes
Create new string using ASCII.
Here is the code :
private String encrypt(String src) {
byte[] srcBytes = src.getBytes(StandardCharsets.US_ASCII);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);
byte[] cipherText = cipher.doFinal(srcBytes);
byte[] encryptedBytes = new byte[12 + cipherText.length];
System.arraycopy(ivBytes, 0, encryptedBytes, 0, 12);
System.arraycopy(cipherText, 0, encryptedBytes, 12, cipherText.length);
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
}
private String decrypt(String encryptedString) {
byte[] encryptedBytes = Base64.decode(encryptedString, Base64.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, encryptedBytes, 0, 12));
byte[] decryptedBytes = cipher.doFinal(encryptedBytes, 12, encryptedBytes.length-12);
return Base64.encodeToString(decryptedBytes, Base64.DEFAULT);
}
Any variables I didn't include how to initialize them can be inferred from the java docs. I was trying to do this in Android so I'm not sure how different it is. I found this post to be incredibly helpful: Java AES/GCM/NoPadding - What is cipher.getIV() giving me?
you should update section code
error section code:
//What size should be assigned to outputBuffer?
final byte[] data1 = new byte[256];
int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
cipher.update(tag, 0, tag.length, data1, offset);
cipher.doFinal(data1, offset);
update the new code:
final byte[] data1 = new byte[encrypted.length];
int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
offset += cipher.update(tag, 0, tag.length, data1, offset);
cipher.doFinal(data1, offset);
I'm trying to encrypt/decrypt files with PBE using AES. I'm using Bouncy Casle library(lightweight API), because I need to ignoring restrictions on key length. I found function and changed some code in it.
public void decryptLW(InputStream in, OutputStream out, String password, byte[] salt, final int iterationCount) throws Exception {
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(new SHA256Digest());
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes = PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, salt, iterationCount);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams = (ParametersWithIV) pGen.generateDerivedParameters(256, 128);
aesCBC.init(false, aesCBCParams);
PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
try {
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
byte[] plainTemp = new byte[aesCipher.getOutputSize(buf.length)];
int offset = aesCipher.processBytes(buf, 0, buf.length, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
out.write(plain, 0, numRead);
}
out.close();
in.close();
} catch (java.io.IOException e) {
}
}
And I have an error:
org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at org.bouncycastle.crypto.paddings.PKCS7Padding.padCount(Unknown Source)
at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(Unknown Source)
What can I do to remove this error? And what I must to change in this function to get ability to encrypt files.
Finally, I found problem, I don't have initialized aesCipher. When I added method aesCipher.init(true, aesCBCParams); it started working.
And also I changed some code:
int numRead = 0;
while ((numRead = fin.read(buf)) >= 0) {
if (numRead == 1024) {
byte[] plainTemp = new byte[aesCipher.getUpdateOutputSize(numRead)];
int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
final byte[] plain = new byte[offset];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
} else {
byte[] plainTemp = new byte[aesCipher.getOutputSize(numRead)];
int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
}
}
You have a problem with your padding. This may mean that the incoming cyphertext was encrypted with a different padding, not PKCS7. It may mean that the incoming cyphertext was encrypted in a different mode (not CBC). It may mean that you have the wrong key, so the last block decrypts as random. If your message is only one block long then it may mean you have a faulty IV, so again the padding is corrupt.
You need to check that the key, mode, padding and IV are identical at both ends. This means checking key and IV byte by byte.