I am converting my C# encryption code to Android.
I am facing issue like I am not able to encrypt the text as same as C#.
Below I copy paste both code.
Both are working code regarding using it you can use any password & any plain text .You will find both have different output.
C# CODE
System.security.Cryptography.RijndaelManaged AES = new System.Security.Cryptography.RijndaelManaged();
System.Security.Cryptography.MD5CryptoServiceProvider Hash_AES = new System.Security.Cryptography.MD5CryptoServiceProvider();
final MessageDigest Hash_AES = MessageDigest.getInstance("MD5");
String encrypted = "";
try {
byte[] hash = new byte[32];
byte[] temp = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass));
final byte[] temp = Hash_AES.digest(pass.getBytes("US-ASCII"));
Array.Copy(temp, 0, hash, 0, 16);
Array.Copy(temp, 0, hash, 15, 16);
AES.Key = hash;
AES.Mode = System.Security.Cryptography.CipherMode.ECB;
System.Security.Cryptography.ICryptoTransform DESEncrypter = AES.CreateEncryptor();
byte[] Buffer = System.Text.ASCIIEncoding.ASCII.GetBytes(input);
encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length));
} catch (Exception ex) {
}
return encrypted;
Here is my Android java code.
ANDROID JAVA CODE
private static String TRANSFORMATION = "AES/ECB/NoPadding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
byte[] encryptedData;
public RijndaelCrypt(String password,String plainText) {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
_password = new SecretKeySpec(digest.digest(password.getBytes()), ALGORITHM);
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_cipher.init(Cipher.ENCRYPT_MODE, _password);
encryptedData = _cipher.doFinal(text);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
return Base64.encodeToString(encryptedData,Base64.DEFAULT);
}
Should I need to use "US-ASCII" in pass or does it take it?
Use the same mode of operation: either ECB or CBC
Use the same character set: it's best to stick to "UTF-8"
Use the same key: in the C# code you're doubling the 128-bit key to 256 bits
When using CBC with a random IV, it is expected that the ciphertext differs for the same plaintext. The decryption is the operation that determines whether you succeeded.
Note that ECB is not semantically secure. Use CBC with a random IV. The IV doesn't have to be secret, so you can just prepend it to the ciphertext and slice it off before decryption.
It's better to use an authenticated mode like GCM or EAX or if it's not provided an encrypt-then-MAC scheme. It's hard to implement it correctly yourself so stick to some library that does this for you like RNCryptor.
Related
From the php encryption function below:
$data = "1212312121447";
$cipher = "aes-256-ofb";
$secretKey = "aNdRgUjXn2r5u8x/A?D(G+KbPeShVmYp";
$ivLength = openssl_cipher_iv_length($cipher);
$keyOfb = substr(hash('sha256', $secretKey, true), 0, 32);
$ivOfb = substr($keyOfb, 0, $ivLength);
$encryptedOfb = openssl_encrypt($data, $cipher, $keyOfb, OPENSSL_RAW_DATA, $ivOfb);
echo "ofb-encrypted: " . base64_encode($ivOfb . $encryptedOfb);
the result of encryption is MyFTCJx8RPzOx7h8QNxEtQgeiNIRwnrJ+uc0V70=
And I have try to write this function in Java like this:
public static SecretKeySpec hashKey(String key){
String keyPass = key;
SecretKeySpec result = null;
try{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(keyPass.getBytes());
byte[] AesKeyData = Arrays.copyOfRange(md.digest(), 0, 32);
SecretKeySpec keySpec = new SecretKeySpec(AesKeyData, "AES");
result = keySpec;
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return result;
}
public static String encryptedOFB(String inp){
String result = "";
String key = "aNdRgUjXn2r5u8x/A?D(G+KbPeShVmYp";
SecretKeySpec keyHashed = hashKey(key);
try{
byte[] initVectorSize = Arrays.copyOfRange(keyHashed.toString().getBytes(), 0, 16);
Cipher cipher = Cipher.getInstance("AES/OFB/NoPadding");
IvParameterSpec iv = new IvParameterSpec(initVectorSize, 0, cipher.getBlockSize());
cipher.init(Cipher.ENCRYPT_MODE, keyHashed, iv);
byte[] encrypted = cipher.doFinal(inp.getBytes());
ByteArrayOutputStream conc = new ByteArrayOutputStream();
conc.write(initVectorSize);
conc.write(encrypted);
byte[] concEnc = conc.toByteArray();
result = new String(Base64.getEncoder().encode(concEnc));
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return result;
}
The result is amF2YXguY3J5cHRvLnNwZYUmrJNv8ycvLua0O9g=
Why my java function return the different result from php?
And how do I fix the java function to get the same result with php?
Thank you.
The IV is determined wrongly. Instead of keyHashed.toString().getBytes() you have to use keyHashed.getEncoded(). Then you get the result of the PHP code.
Apart from that, your key derivation is insecure: since the IV is the first 16 bytes of the key, the same password also means the same key/IV pair, which is insecure. For passwords, it is better to use a reliable key derivation function in conjunction with a randomly generated salt. The IV can be inferred along with the key or randomly generated independently. Salt (or IV) are not secret and can be passed with the ciphertext for decryption, usually concatenated.
When encoding (e.g. inp.getBytes()), the encoding should always be specified (e.g. StandardCharsets.UTF_8). Likewise with the decoding (new String(..., StandardCharsets.UTF_8)). Otherwise the default encoding is used, which can cause cross-platform problems.
I get this warning:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Any ideas what causes this? Here are my encryption and decryption code. I have looked at a variety of different answers on StackOverflow but I was unable to find one that actually works.
private static Cipher ecipher;
private static Cipher dcipher;
private static SecretKey key;
public static void Menu() {
try {
// generate secret key using DES algorithm
key = KeyGenerator.getInstance("DES").generateKey();
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
// initialize the ciphers with the given key
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (NoSuchAlgorithmException e) {
System.out.println("No Such Algorithm:" + e.getMessage());
return;
} catch (NoSuchPaddingException e) {
System.out.println("No Such Padding:" + e.getMessage());
return;
} catch (InvalidKeyException e) {
System.out.println("Invalid Key:" + e.getMessage());
return;
}
}
public static String encrypt(String WordToEncrypt) {
Menu();
try {
// encode the string into a sequence of bytes using the named charset
// storing the result into a new byte array.
byte[] utf8 = WordToEncrypt.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
// encode to base64
enc = BASE64EncoderStream.encode(enc);
System.out.println(new String(enc));
return new String(enc);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decrypt(String WordToDecrypt) {
Menu();
try {
// decode with base64 to get bytes
byte[] dec = BASE64DecoderStream.decode(WordToDecrypt.getBytes());
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
You call Menu once in the encryption code and once in the decryption code. Since you generate the key randomly for both encryption and decryption, the key will differ and your code will fail.
Don't keep Cipher instances around, preferably not even in fields, but certainly not in class fields. DES is old; too old. Use AES - using DES isn't any easier than AES.
I am encrypting a string using RSA algorithm and encryption and decryption logic is
public class RsaEncrypt {
private static final String ALGORITHM = "RSA";
public static void main(String[] args) {
String filePath = "/home/Desktop/abc.jks";
char[] password = "changeit".toCharArray();
String alias = "123";
KeyStore ks = null;
try {
//loading the keystore
ks = KeyStore.getInstance("JKS");
InputStream readStream = new FileInputStream(filePath);
ks.load(readStream, password);
Certificate cert = ks.getCertificate(alias);
PublicKey publicKey = cert.getPublicKey();
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password);
RsaEncrypt e = new RsaEncrypt();
String result = e.encrypt("abvhdh", publicKey);
String decryptResult = e.decrypt(result.getBytes(), privateKey);
} catch (Exception e) {
e.printStackTrace();
}
}
//Encryption of a string
public String encrypt(String text,PublicKey publicKey) {
String retVal = null;
byte[] cipherText = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
cipherText = Base64.getEncoder().encode(cipherText);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return new String(cipherText) ;
}
// Decryption of a string
private String decrypt(byte[] text, PrivateKey privatekey) {
byte[] dectyptedText = null;
try {
final Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privatekey);
dectyptedText = cipher.doFinal(Base64.getDecoder().decode(text));
} catch (Exception ex) {
ex.printStackTrace();
} catch (Throwable e) {
throw new RuntimeException(e);
}
return new String(dectyptedText);
}
The Result is fine.But if i encrypt same string one more time i am getting different encryption value.
For that i am using "RSA/ECB/NoPadding" cipher instead of "RSA",then If i encrypt one string many times i am getting same encryption value.
But when i decrypt,The reuslt string contains some null characters
Example
input : abcd output : abcd \u0000 \u0000 \u0000 \u0000....
How can i resolve this problem and what is the best way to get same encryption value if we encrypt multiple times?????
The Result is fine.But if i encrypt same string one more time i am getting different encryption value.
That is correct and it is even required property of the RSA encryption. By default PKCS1.5 padding is used (RSA/ECB/PKCS1Padding) which contains some random bytes. Safer option is RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING mode which is even more random.
For that i am using "RSA/ECB/NoPadding" cipher instead of "RSA",then If i encrypt one string many times i am getting same encryption value. But when i decrypt,The reuslt string contains some null characters
Using RSA without padding (NoPadding) is very unsafe (it is called textbook RSA).
Padding extends the original encrypted value to full space length (e.g. 2048 bits) and then the RSA magic (exponentiation) will be executed. Using the NoPadding parameter you are telling the crypto library that you will do the padding yourself. In that case you are expected to remove the padding after decryption (in your case zero padding)
I hope you are doing that for learning / academic purposes, not some real security project. You may have a look at my blog about encryption to get some examples.
btw: you should not use RSA to encrypt the plaintext itself. Rather use symmetric encryption to encrypt the plaintext and then RSA to encrypt the symmetric encryption key.
I have an application developed on BlackBerry JDE 5.0.0 that encrypts a String using DES algorithm with ECB mode. After the encryption, the result is encoded by base64 encoding. But whenever I compare the result that i get from my encryption method with the result that i get on the online encryptor engine, it always give different result on the several last character. I tried to decrypt the result that i get form my encryption method with the online encriptor engine and it looks like the result is not the valid one. So how can I fix that different result on the several last character?
Here my encryption method code:
public String encryptDESECB(String text) throws MessageTooLongException
{
byte[] input = text.getBytes();
byte[] output = new byte[8];
byte[] uid = null;
uid = "431654625bd37673e3b00359676154074a04666a".getBytes();
DESKey key = new DESKey(uid);
try {
DESEncryptorEngine engine = new DESEncryptorEngine(key);
engine.encrypt(input, 0, output, 0);
String x= BasicAuth.encode(new String(output));
System.out.println("AFTER ENCODE"+x);
return new String(x);
} catch (CryptoTokenException e) {
return "NULL";
} catch (CryptoUnsupportedOperationException e) {
return "NULL";
}
}
The String that i want to encrypt is "00123456"
The Result that i get from my encryption method is:YnF2BWFV/8w=
The Result that i get from online encryptor engine (http://www.tools4noobs.com/online_tools/encrypt/) : YnF2BWFV9sw=
The Result that i get from android (With the same encryption algorithm & Method) : YnF2BWFV9sw=
Here's the code on Android:
public static String encryptDesECB(String data) {
try {
DESKeySpec keySpec = newDESKeySpec("431654625bd37673e3b00359676154074a04666a".getBytes("UTF8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);
// ENCODE plainTextPassword String
byte[] cleartext = data.getBytes("UTF8");
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
Logger.log(Log.INFO, new String(cipher.doFinal(cleartext)));
String encrypedPwd = Base64.encodeToString(cipher.doFinal(cleartext), Base64.DEFAULT);
Logger.log(Log.INFO, encrypedPwd);
return encrypedPwd;
} catch (Exception e) {
Logger.log(e);
return null;
}
}
Can anyone help me with this?
This is most likely caused by padding, as DES works with 8 byte blocks.
For more information check out this link:
http://www.tero.co.uk/des/explain.php#Padding
As long as you can properly decrypt the content you'll be fine.
I found my mistake. It turn out my BasicAuth Class isn't the correct one for encoding the encrypted string. Now I'm using the correct one Base64 Class for the encoding, and it turn out fine.
I followed much of this post with the objective to implement aes 256 encryption in my software and it works just fine
The key point here is that the whole implementation described in the above link uses the AESEngine class. Looking at the class code and javadoc reference, the AESEngine is a 128bit instead of a 256 bit block cipher
Searching trough the code and docs i could not find the 192 or 256 bits implementations. Where are them?
For completeness, this is the core of my actual ciphering class:
private void init(String passphrase) {
try {
String algorithm = "PBEWithSHA256And256BitAES-CBC-BC";
encryptCipher = createCipher();
decryptCipher = createCipher();
randomGenerator = new RandomGenerator();
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(), KEY_SALT, ITERATIONS);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
key = keyFactory.generateSecret(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("NoSuchAlgorithmException occured while trying to generate the crypto key. This error should never occur, check the application code", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("InvalidKeySpecException occured while trying to generate the crypto key. This error should never occur, check the application code", e);
}
}
private BufferedBlockCipher createCipher() {
return new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()), new PKCS7Padding());
}
public byte[] encrypt(byte[] data) {
if (data == null)
throw new NullPointerException("Cannot encrypt null data");
byte[] iv = randomGenerator.generateRandom(IV_SIZE);
byte[] encrypted;
synchronized (encryptCipher) {
encrypted = runCipher(encryptCipher, true, data, iv);
}
return DataUtil.append(iv, encrypted);
}
public byte[] decrypt(byte[] data) {
if (data == null)
throw new NullPointerException("Cannot decrypt null data");
byte[] iv = DataUtil.extract(data, 0, IV_SIZE);
byte[] cipherText = DataUtil.extract(data, IV_SIZE, data.length - IV_SIZE);
byte[] decrypted;
synchronized (decryptCipher) {
decrypted = runCipher(decryptCipher, false, cipherText, iv);
}
return decrypted;
}
private byte[] runCipher(BufferedBlockCipher cipher, boolean forEncryption, byte[] data, byte[] iv) {
String operation = forEncryption ? "encrypt" : "decrypt";
try {
KeyParameter keyParam = new KeyParameter(key.getEncoded());
ParametersWithIV cipherParams = new ParametersWithIV(keyParam, iv);
cipher.init(forEncryption, cipherParams);
byte[] result = new byte[cipher.getOutputSize(data.length)];
int len = cipher.processBytes(data, 0, data.length, result, 0);
len += cipher.doFinal(result, len);
//Remove padding se estiver decriptografando
if(!forEncryption)
result = DataUtil.extract(result, 0, len);
return result;
} catch (DataLengthException e) {
throw new RuntimeException("DataLengthException occured while trying to " + operation + " data with length " + data.length + ". This error should never occur, check the application code", e);
} catch (IllegalStateException e) {
throw new RuntimeException("IllegalStateException occured while trying to " + operation + " data with length " + data.length + ". This error should never occur, check the application code", e);
} catch (InvalidCipherTextException e) {
throw new IllegalArgumentException("InvalidCipherTextException occured while trying to " + operation + " data with length " + data.length, e);
}
}
If you want to do AES like encryption with a block size of 256 bit you should use:
http://www.docjar.org/docs/api/org/bouncycastle/crypto/engines/RijndaelEngine.html
But that's probably not what you want; the 256 in AES-256 is about the key size. This key size is then used by the underlying 128 bit AES block cipher. AES is the standardized, 128 bit block version of Rijndael.
AES supports 3 key sizes - Wikipedia, NIST.
You're probably referring the block size, which is fixed at 128 bits.
Also, I tried going through code, it is written assuming different key sizes - 128, 192, and 256. Copy - paste from code - "AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits. This code is written assuming those are the only possible values"