I found the following code on an encryption website ... it works as a Java client and a C# server. This code works great except there is one problem I cannot figure out. If I send small messages everything is fine ... the problem starts when I send more than 47 char to the server at this point it fails with the following error:
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
Can someone look this over or possibly test it for themselves and find a solution … thanks.
Java Code:
public class Crypto {
private final String characterEncoding = "UTF-8";
private final String cipherTransformation = "AES/CBC/PKCS5Padding";
private final String aesEncryptionAlgorithm = "AES";
public byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
cipherText = cipher.doFinal(cipherText);
return cipherText;
}
public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
plainText = cipher.doFinal(plainText);
return plainText;
}
private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
byte[] keyBytes= new byte[16];
byte[] parameterKeyBytes= key.getBytes(characterEncoding);
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
/// <summary>
/// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string
/// </summary>
/// <param name="plainText">Plain text to encrypt</param>
/// <param name="key">Secret key</param>
/// <returns>Base64 encoded string</returns>
public String encrypt(String plainText, String key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
byte[] keyBytes = getKeyBytes(key);
return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes), Base64.DEFAULT);
}
/// <summary>
/// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher)
/// </summary>
/// <param name="encryptedText">Base64 Encoded String</param>
/// <param name="key">Secret Key</param>
/// <returns>Decrypted String</returns>
public String decrypt(String encryptedText, String key) throws KeyException, GeneralSecurityException, GeneralSecurityException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException{
byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT);
byte[] keyBytes = getKeyBytes(key);
return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding);
}
C# Code:
class Crypto
{
public static string currentPassword;
public RijndaelManaged GetRijndaelManaged(String secretKey)
{
var keyBytes = new byte[16];
var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
return new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
KeySize = 128,
BlockSize = 128,
Key = keyBytes,
IV = keyBytes
};
}
public byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateEncryptor()
.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public byte[] Decrypt(byte[] encryptedData, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
}
/// <summary>
/// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string
/// </summary>
/// <param name="plainText">Plain text to encrypt</param>
/// <param name="key">Secret key</param>
/// <returns>Base64 encoded string</returns>
public String Encrypt(String plainText, String key)
{
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key)));
}
/// <summary>
/// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher)
/// </summary>
/// <param name="encryptedText">Base64 Encoded String</param>
/// <param name="key">Secret Key</param>
/// <returns>Decrypted String</returns>
public String Decrypt(String encryptedText, String key)
{
var encryptedBytes = Convert.FromBase64String(encryptedText);
return Encoding.UTF8.GetString(Decrypt(encryptedBytes, GetRijndaelManaged(key)));
}
}
Related
I try to decrypt to json response in Android from node js server and it does not decrypt it correctly. But it decrypted correctly a string or JSONArray. When i decrypt json object in node js from android, it decrypts correctly. Can you help me to understand what is wrong?
Node js
function encryptDataTestWork(text, masterkey) {
// body...
// random initialization vector
const iv = crypto.randomBytes(16);
// random salt
const salt = crypto.randomBytes(64);
// derive encryption key: 32 byte key length
// in assumption the masterkey is a cryptographic and NOT a password there is no need for
// a large number of iterations. It may can replaced by HKDF
// the value of 2145 is randomly chosen!
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512');
// AES 256 GCM Mode
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
const encrypted = Buffer.concat([
cipher.update(text, 'utf8'),
cipher.final()
]);
// extract the auth tag
const tag = cipher.getAuthTag();
// generate output
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
};
let item = JSON.stringify({name:'Selemani',lastName:'Jimmy'});
let generatedKey = 'SEXFgk1kQ3BcDzrH';
let encryptedMobile = encryptDataTestWork(item, generatedKey);
console.log('data->[encrypted] -> '+encryptedMobile);
res.send({tag: 'success', data: encryptedMobile, key: generatedKey});
And Android code
private final static int GCM_TAG_LENGTH = 16;
public static String decryptHelper(String algorithm, byte[] cipherText, byte[] tag,SecretKey key,
GCMParameterSpec gcmParameterSpec) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
cipher.update(cipherText);
byte[] plainText = cipher.doFinal(tag);
return new String(plainText, StandardCharsets.UTF_8);
}
public static String decrypt(String encData, String masterKey) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
byte[] cipherText;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
cipherText = Base64.getDecoder().decode(encData.getBytes(StandardCharsets.UTF_8));
}else{
cipherText = android.util.Base64.decode(encData.getBytes(StandardCharsets.UTF_8), android.util.Base64.DEFAULT);
}
byte[] salt = Arrays.copyOfRange(cipherText, 0, 64);
byte[] iv = Arrays.copyOfRange(cipherText, 64, 80);
byte[] tag = Arrays.copyOfRange(cipherText, 80, 96);
byte[] ciphertext = Arrays.copyOfRange(cipherText, 96, cipherText.length);
SecretKey key = getKeyFromPassword(masterKey, salt);
return decryptHelper("AES/GCM/NoPadding", ciphertext, tag, key, new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv));
}
Here is what i see in logs
Data Response: {"tag":"success","data":"yMiFnU7JNhCtFY1buCO5kGgj8rOm3L+iAr9JxBwziMiPes4mHctcvX+V2crOncOQeLKikGo+RY82mOrKu4DWhhmejdI+/UDHWYqs2k54w4SDED8IeJzZ+1kM5mgB+WMMWI6zb5+9r6TAb6ThBFoE6Ot3dajtvVUe6LwGGiUugViNCGtu","key":"SEXFgk1kQ3BcDzrH"}
2022-04-30 12:29:46.298 28249-28281/com.hello.app E/HttpConnexion: n(JSON_OBJECT=key): SEXFgk1kQ3BcDzrH
2022-04-30 12:29:46.337 28249-28281/com.hello.app E/HttpConnexion: Decrypted: "lastName":"Jimmy"}// decrypted text i get. It should be {name:'Selemani',lastName:'Jimmy'}
2022-04-30 12:29:46.338 28249-28281/com.hello.app W/System.err: org.json.JSONException: Value lastName of type java.lang.String cannot be converted to JSONObject
If i send a string like "Hello World", it correctly decrypts.
I did what #Topaco said and it worked!
public static String decryptHelper(String algorithm, byte[] cipherText, byte[] tag,SecretKey key,
GCMParameterSpec gcmParameterSpec) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
byte[] plain = cipher.update(cipherText);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(plain);
byte[] plainText = cipher.doFinal(tag);
outputStream.write(plainText);
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
}
Thank you! #Topaco You saved me!
I'm trying to encrypt and decrypt some text using AES algorithm like :
private static final String ALGORITHM = "AES";
private static final String MODE = "AES/CBC/PKCS7Padding";
public String encrypt(String value, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(key.getBytes()));
byte[] values = cipher.doFinal(value.getBytes());
return Base64.encodeToString(values, Base64.URL_SAFE);
}
public String decrypt(String value, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] values = Base64.decode(value, Base64.DEFAULT);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(key.getBytes()));
return new String(cipher.doFinal(values));
}
The encrypting code works perfectly fine but when I'm trying to decrypt the encrypted text it returns a bad base64 error.
What I tried to do before:
I already tried to change Base64.DEFAULT to Base64.URL_SAFE but it gave me the same error.
Also, I tried to replace "/" and "+" with "_" and "-" and it doesn't work either.
Heres the value I'm encrypted and trying to decrypt:
Ssg2w+dv7es7/wWAeAcoAOSVnYKsoLlefbmS8tYr+jc=
Thanks for helping...
In order for me to consume a webservice, I need to generate a value for an header named Authorization. The steps to generate the header is as follows:
1. Hash Generation
HashValue = SHA2(username, password, id)
2. Auth Key Generation
Authkey = AES(Salt + anotherId + "=" + HashValue)
These are the algorithms details:
Algorithm - AES
Mode - ECB
Padding - PKCS5Padding
Secret key - someString
Now I will be performing the AES encryption using the above details and the secret key which is a string.
After the encryption, I will use the above generated encrypted value as a header in my rest service call.
I have done this so far:
String username = "username";
String password = "password";
String id = "123456";
String toBeHashed = username + password + id;
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] hashed = sha256.digest(toBeHashed.getBytes("UTF-8"));
String hashString = "=" + Base64.encodeBase64String(hashed);
System.out.println(hashString);
String salt = "salt";
String anotherId = "123";
byte[] forAuth = (salt + orgId + hashString).getBytes("UTF-8");
//Mocked "secret key". Original key string is of size 16 bytes.
byte[] secKey = "secret key".getBytes("UTF-8");
SecretKey secretKey = new SecretKeySpec(secKey, 0, secKey.length, "AES");
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] authorizationKey = aesCipher.doFinal(forAuth);
System.out.println("-------------------");
System.out.println("-------------------");
System.out.println(Base64.encodeBase64String(authorizationKey));
But still the backend service says that my authorization key is invalid. Please tell me if I am missing something.
**Encrypt and Decrypt using AES**
public static String encrypt(String value) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec iv = new IvParameterSpec("randomStringVec".getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec("randomStringKey".getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(1, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
}
public static String decrypt(String encrypted) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec iv = new IvParameterSpec("randomStringVec".getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec("randomStringKey".getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(2, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
}
**Encryption Using SHA256**
private static String encrypt256(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest crypt = MessageDigest.getInstance("SHA-256");
crypt.reset();
crypt.update(password.getBytes("UTF-8"));
return new BigInteger(1, crypt.digest()).toString(16);
}
You need to change this:
String hashString = "=" + Base64.encodeBase64String(hashed);
System.out.println(hashString);
To:
String hashString = "=" + new String(hashed);
System.out.println(hashString);
Since the hashed key is getting base64encoded before the authorization key generation.
I'm using a snippet to decrypt an AES file.
However, i'd like to use a key file instead of a password to decrypt the file.
What changes do i need to make in the code below to make that happen?
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AESCrypto {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return Converters.toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = Converters.toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
public static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(seed);
try {
kgen.init(256, sr);
} catch (Exception e) {
// Log.w(LOG, "This device doesn't support 256 bits, trying 192 bits.");
try {
kgen.init(192, sr);
} catch (Exception e1) {
// Log.w(LOG, "This device doesn't support 192 bits, trying 128 bits.");
kgen.init(128, sr);
}
}
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
}
An AES key is little more than 16, 24 or 32 bytes of randomly generated data. So to create a key file, save that amount of random data in it, and use it to instantiate SecretKeySpec(byte[] data, "AES").
Note that for your convenience SecretKeySpec is also a SecretKey.
In my Android app I am communicating with a web service the data sent and responded are encrypted with AES encryption.
So what I do is the following. I'm sending a base64 encoded AES encrypted JSON String to share.php
Share.php will then decrypt this string and insert it into the database. After that the PHP will encrypt en encode the response.
My Android application then needs to decode en decrypt this message.
But the decryption of the PHP response is not going very well.
This is my AES.java:
public class AES {
private final String characterEncoding = "UTF-8";
private final String cipherTransformation = "AES/ECB/PKCS5Padding";
private final String aesEncryptionAlgorithm = "AES";
public byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
//IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
//cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy);
System.out.println("Do final: "+cipherText);
cipherText = cipher.doFinal(cipherText);
return cipherText;
}
public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
//IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
//cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
plainText = cipher.doFinal(plainText);
return plainText;
}
private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
byte[] keyBytes= new byte[16];
byte[] parameterKeyBytes= key.getBytes(characterEncoding);
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
/// <summary>
/// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string
/// </summary>
/// <param name="plainText">Plain text to encrypt</param>
/// <param name="key">Secret key</param>
/// <returns>Base64 encoded string</returns>
public String encrypt(String plainText, String key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
byte[] keyBytes = getKeyBytes(key);
//return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes), Base64.DEFAULT);
return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, new byte[0]), Base64.DEFAULT);
}
/// <summary>
/// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher)
/// </summary>
/// <param name="encryptedText">Base64 Encoded String</param>
/// <param name="key">Secret Key</param>
/// <returns>Decrypted String</returns>
public String decrypt(String encryptedText, String key) throws KeyException, GeneralSecurityException, GeneralSecurityException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException{
byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT);
byte[] keyBytes = getKeyBytes(key);
//return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding);
return new String(decrypt(cipheredBytes, keyBytes, new byte[0]), characterEncoding);
}
}
And this is the code to encode en encrypt the response in PHP:
function mc_encrypt($encrypt, $mc_key) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$passcrypt = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $mc_key, trim($encrypt), MCRYPT_MODE_ECB, $iv));
$encode = base64_encode($passcrypt);
return $encode;
}
function mc_decrypt($decrypt, $mc_key) {
$decoded = base64_decode($decrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $mc_key, trim($decoded), MCRYPT_MODE_ECB, $iv));
return $decrypted;
}
I'm guessing that the settings of the PHP encryption do not match the settings for the Java part. Can
I'm getting the following error:
03-12 13:44:09.661: W/System.err(15717): javax.crypto.BadPaddingException: pad block corrupted
I suggest you take a look at http://phpaes.com/. It's a free AES encryption library implemented purely in PHP; it's fast and very very simple to use.
At the very least, it allows you get one step closer to isolating the true source of the issue.
This might not be the answer you're looking for - but is there a specific reason you're manually encrypting this data instead of using SSL/HTTPS?
In most cases HTTPS will be easier to implement and more secure than manually implementing a symmetric cipher.