Port Java AES ECB encryption into UWP compatible C# Code - java

I am very new in the field of cryptography and have been stuck on this problem for two days.
I have a java code for AES/ECB encryption and I want my uwp app to use the same encryption technique but whatever I've tried so far gives different encryption results.
There are many answers on stackoverflow suggesting to use RijndaelManaged class, but this class is not available for UWP.
Here's java snippet
public string encrypt(String input, string key) {
SecretKeySpec skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey);
crypted = cipher.doFinal(input.getBytes("UTF-8"));
return Base64.encodeToString(crypted,Base64.NO_WRAP);
}

You need to use this answer to see how to encrypt/decrypt. However, you need a different (ECB so insecure) algorithm. So instead of the given CBC cipher mode you need to use AesEcbPkcs7 from the SymmetricAlgorithmNames.
Notes:
PKCS#7 is the same as PKCS#5 as used in the Java code, more info here;
you of course don't need to use an IV for ECB mode, so strip that out;
the UTF-8 encoding and base 64 decoding I'll leave out, it should be easy to do these encodings in any language/environment (the Convert and UTF8Encoding classes seem to be available for UWP apps).

Related

PHP crypt(pass, salt) alternative in Java - Blowfish algorithm

I'm using on php server function crypt like this:
$hash = crypt($password, '$2y$10$' . $salt);
It makes hash of password by Blowfish method.
I'm looking for java equivalent for crypt password.
I found this code, but I don't know where add $salt. More above:
String key = "abcd";
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(cipher.ENCRYPT_MODE, keySpec);
return DatatypeConverter.printBase64Binary(cipher.doFinal(key.getBytes()));
Thank's for every idea or answer.
Not an answer to your question but maybe it helps:
There is the Apache Commons Codec library that contains a Linux crypt(3) compatible function for at least des,md5,sha256 and sha512 based crypt() algorithms in case you don't really need blowfish but just something stronger than the traditional DES based hashes (use sha512 then):
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java?view=markup
And there's other source code that implements the Blowfish algorithm but it's in C:
http://doxygen.postgresql.org/crypt-blowfish_8c_source.html
As you can see crypt() uses algorithms that are only based on those encryption ciphers but pipes the input several thousant times through them to get a nice hash value.
Now I did found some java implementations of crypt(3) with blowfish:
http://www.mindrot.org/projects/jBCrypt/ (last update 2010)
and
http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/apidocs/org/springframework/security/crypto/bcrypt/BCrypt.html

Explanation to understand AES encryption code

I am creating a project to encrypt and decrypt a file. I have these two algorithms that work fine:
public 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;
}
public 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;
}
public static byte[] getRaw(String password_) throws Exception {
byte[] keyStart = password_.getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(keyStart);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
return key;
}
Now I need to explain how it works. Does it use a private key? Where is the key storage? Can anyone help me?
Note: see owlstead's answer for an excellent description of the flaws in your code example
Your encrypt() and decrypt() operations are performing AES encryption and decryption respectively, using Java's JCE libraries. A JCE provider will be selected to perform the actual cryptography - the provider chosen will be the first in the list of providers that offers an implementation of AES. You have defined the algorithm as only "AES", so the mode of operation and padding will be chosen by the provider. If you want to control this, use the form "AES/mode/padding" (see the docs for valid choices)
The getRaw method derives an AES key from a password. The raw bytes of the password provide the seed for a random number generator. The random number generator is then used to generate sufficient key material for a 128-bit AES key. A different password will produce a different seed, which should produce a different stream of random bytes and thus a different key. I suspect this approach is weakened by the lack of entropy present in most people's passwords, leading to a reduced key space and easier attacks.
There is no key storage in your example code. JCE keys are normally persisted using a KeyStore object and the storage mechanism is provider-dependent.
The above piece of code is a bunch of crap. Unfortunately it is frequently used as a code snippet for Android related code (Android code uses the same API as Java, so there is no need for an Android specific example, andt unfortunately it specifically fails on Android).
I'll explain the issues:
Using a SecureRandom as Password Based Key Derivation Function (PBKDF) is completely idiotic. The underlying implementation of the SecureRandom implementation may change. Furthermore, it is not specified by the SecureRandom that calling setSeed() as the first method will replace the seed; it may actually add the seed to the current state - and this is what certain newer android versions do.
Cipher.getInstance("AES") actually uses the provider defaults instead of specifying the mode of operation and padding mode for the given cipher. By default the Sun provider will use ECB mode which is not suitable for encrypting most data.
String.getBytes() - which is used for the password - returns the platform default encoding. Different platforms may have different default encodings. This means that different platforms will generate different keys.
Above code does not add a message authentication code (MAC or HMAC). This may lead to an attacker changing random ciphertext blocks, which leads to random plain text blocks. This may lead to loss of confidentiality as well if padding Oracle attacks apply.
It seems to me that you are a beginner in cryptography. Please use a higher level standard such as RNCryptor compatible code, or use a standard such as Cryptographic Message Syntax (CMS).

Cipher: What is the reason for IllegalBlockSizeException?

I have observed the following when I worked with Cipher.
Encryption code:
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
Decryption code :
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
I get IllegalBlockSizeException ( Input length must be multiple of 16 when ...) on running the Decrypt code.
But If I change the decrypt code to
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); //I am passing the padding too
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
It works fine.
I understand that it is in the pattern algorithm/mode/padding. So I thought it is because I didn't mention the padding. So I tried giving mode and padding during encryption,
Encryption code:
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");//Gave padding during encryption too
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
Decryption code :
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());
But it fails with IllegalBlockSizeException.
What is the reason, why the exception and what is exactly happening underneath.
If anyone can help? Thanks in advance
UPDATE
Looks like the issue is with the string I am encrypting and decrypting. Because, even the code that I said works, doesn't always work. I am basically encrypting UUIDs (eg : 8e7307a2-ef01-4d7d-b854-e81ce152bbf6). It works with certain strings and doesn't with certain others.
The length of encrypted String is 64 which is divisible by 16. Yes, I am running it on the same machine.
Method for secret key generation:
private Key generateKey() throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA");
String passphrase = "blahbl blahbla blah";
digest.update(passphrase.getBytes());
return new SecretKeySpec(digest.digest(), 0, 16, "AES");
}
During decryption, one can only get an IllegalBlockSizeException if the input data is not a multiple of the block-size (16 bytes for AES).
If the key or the data was invalid (but correct in length), you would get a BadPaddingException because the PKCS #5 padding would be wrong in the plaintext. Very occasionally the padding would appear correct by chance and you would have no exception at all.
N.B. I would recommend you always specify the padding and mode. If you don't, you are liable to be surprised if the provider changes the defaults. AFAIK, the Sun provider converts "AES" to "AES/ECB/PKCS5Padding".
Though I haven't fully understood the internals, I have found what the issue is.
I fetch the encrypted string as a GET request parameter. As the string contains unsafe characters, over the request the string gets corrupted. The solution is, to do URL encoding and decoding.
I am able to do it successfully using the URLEncoder and URLDecoder.
Now the results are consistent. Thanks :)
I would be grateful if anyone can contribute more to this.

Java RSA Encryption Non-Repeatable?

I've been having trouble encrypting with an RSA public key. Here is a sample JUnit code that reproduces the problem:
public class CryptoTests {
private static KeyPair keys;
#BeforeClass
public static void init() throws NoSuchAlgorithmException{
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = CryptoUtils.getSecureRandom();
keyGen.initialize(2176, random);
keys = keyGen.generateKeyPair();
}
#Test
public void testRepeatabilityPlainRSAPublic() throws EdrmCryptoException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
byte[] plaintext = new byte [10];
Random r = new Random();
r.nextBytes(plaintext);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted1 = rsa.doFinal(plaintext);
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted2 = rsa.doFinal(plaintext);
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
byte[] encrypted3 = rsa.doFinal(plaintext);
assertArrayEquals(encrypted1, encrypted2);
assertArrayEquals(encrypted1, encrypted3);
}
}
The result? The assertion fails.
Why is this behaviour seen here? As far as I remember from my crypto classes, any key can be used for encryption. Yet this is not what happens here.
I've tested the same thing with the private key, and I get a repeatable output.
If, for some reason, RSA encryption with a public key is forbidden, then why am I not getting an exception?
What must I do to get repeatable results?
P.S. My JDK is 1.6.0_22 running on an Ubuntu 10.10 box.
My guess is that it's applying randomized padding, precisely to make it more secure. From the RSA wikipedia page:
Because RSA encryption is a deterministic encryption algorithm – i.e., has no random component – an attacker can successfully launch a chosen plaintext attack against the cryptosystem, by encrypting likely plaintexts under the public key and test if they are equal to the ciphertext. A cryptosystem is called semantically secure if an attacker cannot distinguish two encryptions from each other even if the attacker knows (or has chosen) the corresponding plaintexts. As described above, RSA without padding is not semantically secure.
...
To avoid these problems, practical RSA implementations typically embed some form of structured, randomized padding into the value m before encrypting it. This padding ensures that m does not fall into the range of insecure plaintexts, and that a given message, once padded, will encrypt to one of a large number of different possible ciphertexts.
You can confirm that what is happening is that random padding is being added by initialising your Cipher with the string "RSA/ECB/NoPadding". Now, you should see that the ciphertext is identical in each case (though for reasons stated by another answerer, you shouldn't really do this in practice).
To add extra detail to Jon's answer:
When you do Cipher.getInstance("...") you have a number of options, as you've probably gathered. The Standard Algorithm Names specify what these are.
The one you asked for, RSA is by default RSA under PKCS1, which, to quote the wikipedia article:
There are two schemes for encryption
and decryption:
RSAES-OAEP: improved encryption/decryption scheme; based on
the Optimal Asymmetric Encryption
Padding scheme proposed by Mihir
Bellare and Phillip Rogaway.
RSAES-PKCS1-v1_5: older encryption/decryption scheme as first
standardized in version 1.5 of PKCS#1.
See RSALab's PKCS1 documentation for the detail of said padding schemes.

Duplicate Oracle DES encrypting in Java

I recently asked a question about Oracle Encryption. Along the way to finding a solution for myself I decided to move the encryption (well, obfuscation) to the application side for certain tasks.
My problem is that the database is already encrypting data a certain way and I need Java code to duplicate that functionality, so that text encrypted by one system can be decrypted by the other and vice versa.
I want the encryption to be compatible with what the DB was already doing but couldn't find the documentation that describes exactly what Oracle is doing. How do I replicate this in Java?
dbms_obfuscation_toolkit.DESEncrypt(
input_string => v_string,
key_string => key_string,
encrypted_string => encrypted_string );
RETURN UTL_RAW.CAST_TO_RAW(encrypted_string);
No matter what I try, it seems as if the Java DES encryption is different than Oracle's.
I found this works:
KeySpec ks = new DESKeySpec(new byte[] {'s','e','c','r','e','t','!','!'});
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey sk = skf.generateSecret(ks);
Cipher c = Cipher.getInstance("DES/CBC/NoPadding");
IvParameterSpec ips = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0});
c.init(Cipher.ENCRYPT, sk, ips);
// or
c.init(Cipher.DECRYPT, sk, ips);
The missing piece was the Initialization Vector (ips) which must be 8 zeros. When you use null in Java you get something different.
Using Java in the database would have been another approach that would (should!) have guarenteed that the code (and hence results) would be identical.

Categories

Resources