I have a password string in my android application. I need to the send the password through the .net web service (i.e. end with .aspx) using the SOAP web service. Before sending the password i need to encrypt the password with AES 128 encryption with the custom key and IV.
They have a encrypt/decrypt tool in .net with the custom key and Iv. The tool ask a custom key with 16 digit and IV 8 digit. If give the string it generate the encrypting string. example
Example:
Key : 1234567812345678
IV : 12345678
String : android
Encrypted string : oZu5E7GgZ83Z3yoK4y8Utg==
I didn't have any idea how to do this in android. Need help.
A complete example may help you:
The encrypt/decrypt functions, using IV
public static byte[] encrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
You can use it as below :
String dataToEncryptDecrypt = "android";
String encryptionDecryptionKey = "1234567812345678";
String ivs = "12345678";
byte[] encryptedData = encrypt(dataToEncryptDecrypt.getBytes(), encryptionDecryptionKey.getBytes(),
ivs.getBytes());
// here you will get the encrypted bytes. Now you can use Base64 encoding on these bytes, before sending to your web-service
byte[] decryptedData = decrypt(encryptedData, encryptionDecryptionKey.getBytes(), ivs.getBytes());
System.out.println(new String(decryptedData));
I don't know the details of AES algorithm in use(ie mode & padding method), bit it should be roughly like this:
public static byte[] encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] empty = new byte[16]; // For better security you should use a random 16 byte key!!!
IvParameterSpec ivps = new IvParameterSpec(empty);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
// ...
}
return null;
}
Function above could be used like this:
String data = "android";
String key = "1234567812345678";
byte encrypted = encrypt(data.getbytes("UTF-8"), key.getbytes("UTF-8"));
Related
I want to encrypt the data in flutter using the AES cbc-128 algorithm. below is the java code for that i want to achieve the same functionality as below but in dart. i have tried
cryptography
dependency in flutter but the problem with that is that i want to use my own key in the algorithm as below in the java code. if you know any method for achieving this please let me know.
public static String Decrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
BASE64Decoder decoder = new BASE64Decoder();
byte[] results = cipher.doFinal(decoder.decodeBuffer(text));
return new String(results, "UTF-8");
}
public static String Encrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(results);
}
Test Case
For the following input
plainText="This is plain text";
key="sahtojetrout2";
i want the encrypted result to be
encryptedText="8FmSMnDsFJVyNUXunhJLSmhFnRq89fl5DyTp0wdYfgk=";
which Topaco has written in an online editor you can check out that here Java Code. In flutter i have tried the program given at the Flutter site
You can do AES CBC-128 encryption in flutter with the help of crypt library. It supports the AES cbc encryption. The following sample code accepts key-string and plain-text as arguments and encrypts it as you have mentioned. You can pass your own key here. For AES-128, you need 128 bit key or 16 character string.
import 'package:encrypt/encrypt.dart';
void main() {
final key = "Your16CharacterK";
final plainText = "lorem ipsum example example";
Encrypted encrypted = encrypt(key, plainText);
String decryptedText = decrypt(key, encrypted);
print(decryptedText);
}
String decrypt(String keyString, Encrypted encryptedData) {
final key = Key.fromUtf8(keyString);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
final initVector = IV.fromUtf8(keyString.substring(0, 16));
return encrypter.decrypt(encryptedData, iv: initVector);
}
Encrypted encrypt(String keyString, String plainText) {
final key = Key.fromUtf8(keyString);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
final initVector = IV.fromUtf8(keyString.substring(0, 16));
Encrypted encryptedData = encrypter.encrypt(plainText, iv: initVector);
return encryptedData;
}
In the above example, the IV is created from the key itself to keep the code easy to read. Use random data for IV for better security. Referred article for flutter encryption.
Currently having issues with the decryption of an AES hash.
When i encrypt using AES256 i get the following result (After base64 encoding)
07sKQfb9dN86XAMxFmVKHQAAAAAAAAAAAAAAAAAAAAA=
I believe my issue is with the AAAAAAAA etc. for some reason I think anyway the padding isn't being removed during decryption.
My code
public String encrypt(String key, String initVector, String value) throws Exception {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"), 0, initVector.getBytes().length);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), 0, key.getBytes().length, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = new byte[32];
cipher.doFinal(value.getBytes(), 0, value.getBytes().length, encrypted, 0);
System.out.println("Base64: " + Base64.encode(encrypted));
System.out.println("Hex: " + bytesToHex(encrypted));
return Base64.encode(encrypted);
}
public String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"), 0, initVector.getBytes().length);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), 0, key.getBytes().length, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] decrypted = new byte[64];
cipher.doFinal(Base64.decode(encrypted), 0, Base64.decode(encrypted).length, decrypted, 0);
return new String(decrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
What i am expecting when i encode base64 07sKQfb9dN86XAMxFmVKHQ=
String i am encrypting: Test
Secret key: password12345678password12345678
byte[] decrypted = new byte[64];
you created a 64 byte array but the decrypted value may be shorter (Java doesn't use zero string terminator unlike C does). So you should not make assumption over the parameter length
try using
encrypted = cipher.doFinal(value.getBytes());
and
decrypted = cipher.doFinal(Base64.decode(encrypted));
I have my application's UI built in Meteor and it gets and send the data from REST API (Spring CXF). I would like to encrypt the data in Meteor, and decrypt the same in REST API code. I am using AES for encryption and Decryption. In Meteor i am using https://atmospherejs.com/jparker/crypto-aes package for encryption. I have written the below code in java for decryption the encryption key send by Meteor.
public class AESTest {
private static String AESStr = "<Encrypted KEY>";
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
System.out.println(decrypt(AESStr, "Test"));
}
public static String decrypt(String responseStr, String passPhrase) throws GeneralSecurityException {
String decryptedStr = "";
try {
Cipher cipher = getCipher(Cipher.DECRYPT_MODE, passPhrase);
byte[] decoded = Base64.decodeBase64(responseStr.getBytes());
byte[] decryptedWithKey = cipher.doFinal(decoded);
byte[] decrypted = Arrays.copyOfRange(decryptedWithKey, 16, decryptedWithKey.length);
decryptedStr = new String(decrypted, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return decryptedStr;
}
private static Cipher getCipher(int mode, String passPhrase) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(passPhrase.getBytes(), "AES");
byte[] IV = new byte[16];
new Random().nextBytes(IV);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(IV);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(mode, secretKeySpec, paramSpec);
return cipher;
}
}
When I run the code i am getting below exception
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.tph.r3.EncodeTest.decrypt(EncodeTest.java:37)
at com.tph.r3.EncodeTest.main(EncodeTest.java:26)
Can anyone guide me with the issue?
There is a problem with the decryption logic w.r.t IV. You are selecting an IV randomly to initialize decryption cipher which is wrong. You need to use the same IV that was used to encrypt the responseStr which forms its first 16 bytes usually.
In the current form your getCipher() can be used only for encryption where IV is selected randomly but not for decryption. Better write another method.
Psuedocode for decryption:
decCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(securityKey , "AES");
//IV + Cipher
byte [] cipherWithIV = Base64.decodeBase64(responseStr.getBytes()));
//Extract IV
byte [] iv = new byte [16];
byte [] cipherWithoutIV = new byte [cipherWithIV.length - 16 ];
//First 16 bytes
for(i < 16; i++) {
iv [i] = cipherWithIV [i];
}
//Rest of the cipher ie 16 -> cipherWithIV.length
for(i < cipherWithIV.length; i++) {
cipherWithoutIV [j] = cipherWithIV[i];
j++;
}
//
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
//
decCipher.init(Cipher.DECRYPT_MODE, keySpec, ivParamSpec);
//Decrypt cipher without IV
decText = decCipher.doFinal(cipherWithoutIV);
//Convert to string
decString = new String(decText,"UTF8");
I'm trying to encrypt something, and decrypt it. I'm failing on the decryption - I get the exception above. I tried changing ctLength and ptLength, but to no avail. What am I doing wrong?
I'm trying to encrypt: 0 0 0 0 0 0 0 0
private Cipher encrypt(byte[] input)
{
try
{
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
FileOutputStream fs = new FileOutputStream(savedScoresFileName);
fs.write(cipherText);
return cipher;
}
catch (Exception e)
{
Log.e("encrtypt", "Exception", e);
}
return null;
}
private String decrypt()
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
byte[] cipherText = new byte[32];
FileInputStream fl = new FileInputStream(savedScoresFileName);
fl.read(cipherText);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(32)];
int ptLength = cipher.update(cipherText, 0, 32, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
return new String(plainText).substring(0, ptLength);
}
catch (Exception e)
{
Log.e("decrypt", "Exception", e);
}
return null;
}
This code was copied from this, which worked.
Your code has a number of issues, but your problem is caused by your file reading code and your strange method of performing the encryption and decryption.
Don't use the update() method, just use doFinal() and correct your file writing/reading code. E.g. your decryption method should look something like:
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
// Here you need to accurately and correctly read your file into a byte
// array. Either Google for a decent solution (there are many out there)
// or use an existing implementation, such as Apache Commons commons-io.
// Your existing effort is buggy and doesn't close its resources.
byte[] cipherText = FileUtils.readFileToByteArray(new File(savedScoresFileName));
cipher.init(Cipher.DECRYPT_MODE, key);
// Just one call to doFinal
byte[] plainText = cipher.doFinal(cipherText);
// Note: don't do this. If you create a string from a byte array,
// PLEASE pass a charset otherwise your result is platform dependent.
return new String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
I have generated on my android application a pair of RSA Keys.
I receive from a web service
- an AES Key, encrypted with my RSA public key
- a String encoded with the AES key.
So I must do the following:
- decrypt the AES Key
- decrypt the string with the obtained AES Key.
To generate the RSA Keys I did:
keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(size);
keypair = keyGen.genKeyPair();
privateKey = keypair.getPrivate();
publicKey = keypair.getPublic();
On RSA decrypt I use :
public static byte[] decryptRSA( PrivateKey key, byte[] text) throws Exception
{
byte[] dectyptedText = null;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
return dectyptedText;
}
On AES decrypt I use:
public static byte[] decryptAES(byte[] key, byte[] text) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(text);
return decrypted;
}
So, in my code, to obtain the decrypted AES Key I do
byte[] decryptedAESKey = sm.decryptRSA(key, Base64.decode(ReceivedBase64EncryptedAESKey));
byte[] decryptedString = sm.decryptAES(decryptedAESKey, Base64.decode(ReceivedEncryptedAESString));
On the end I get a null for decryptedString.
What am I doing wrong ?
Well, the thing is that the key decrypted was 8 byte long and I had to make it 16 byte to be AES 128 bits compatible
So, I made a method to convert it back
private static byte[] GetKey(byte[] suggestedKey)
{
byte[] kRaw = suggestedKey;
ArrayList<Byte> kList = new ArrayList<Byte>();
for (int i = 0; i < 128; i += 8)
{
kList.add(kRaw[(i / 8) % kRaw.length]);
}
byte[] byteArray = new byte[kList.size()];
for(int i = 0; i<kList.size(); i++){
byteArray[i] = kList.get(i);
}
return byteArray;
}
And the rewritten decrypt method:
public static byte[] decryptAES(byte[] key, byte[] text) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(GetKey(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
byte [] iv = new byte[cipher.getBlockSize()];
for(int i=0;i<iv.length;i++)iv[i] = 0;
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
byte[] decrypted = cipher.doFinal(text);
return decrypted;
}
I'm not sure what language or libraries you are using (looks like Java?), but some really general things to try:
Did you get the encrypted string, ok? Check the length of ReceivedEncryptedAESString and the output of the Base64.decode to check they look alright.
AES decryption can't fail so it must be a problem in the library initialisation. Check the value/state of cipher after the construction step and the init step.
Try a simpler testcase: ignore the RSA encryption and just try to decrypt something using your Cipher object.