Can KeyGenerator with SecureRandom("SHA1PRNG") be implemented in .Net Framework? - java

I'm hitting a brick wall, I hope someone can help. I have to encrypt a string that will be decrypted somewhere else (not under my control), as part of an authentication mechanism.
I'm told it uses a cipher "AES/ECB/PKCS5Padding", and I was given a 128 bit encryption key.
After implementing this in C#, it doesn't match the expected output.
While poking around a .jar I got my hands on, it seems that the encryption key is used in a different way than I was expecting, and I haven't figured out how, or even if it can, be ported to C#. Java:
String secretKey = "1234567890abcdef" //example
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom sRandom = SecureRandom.getInstance("SHA1PRNG");
sRandom.setSeed(secretKey.getBytes("UTF-8"));
keyGen.init(128, sRandom);
SecretKey generatedKey = keyGen.generateKey();
byte[] encodedKey = generatedKey.getEncoded();
SecretKeySpec realKey = new SecretKeySpec(encodedKey, "AES");
Cipher cipherInstance = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
cipherInstance.init(1, realKey);
String encryptedText bytesToHexString(cipherInstance.doFinal("text to encode".getBytes("UTF-8")));
I think I've got it all down except generating the encodedKey above.
Can someone shed some light please? :)
EDIT: The example above should produce 4a031f9da16717d442c0d06c415435b5 I believe.

Related

Bouncy Castle vs Java default RSA with OAEP

Can someone explain to me why this code throws javax.crypto.BadPaddingException: Decryption error on the final line when it's decrypting the key?
// Given an RSA key pair...
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// ... and an AES key:
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey aesKey = keyGenerator.generateKey();
// When I encrypt the key with this Bouncy Castle cipher:
Cipher encryptionCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", "BC");
encryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedKey = encryptionCipher.doFinal(aesKey.getEncoded());
// Then trying to decrypt the key with this cipher...
Cipher decryptionCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
decryptionCipher.init(Cipher.DECRYPT_MODE, privateKey);
// ... throws `javax.crypto.BadPaddingException: Decryption error` here:
decryptionCipher.doFinal(encryptedKey);
Is the following statement from https://stackoverflow.com/a/27886397/66722 also true for RSA with OAEP?
"RSA/ECB/PKCS1Padding" actually doesn't implement ECB mode encryption.
It should have been called "RSA/None/PKCS1Padding" as it can only be
used to encrypt a single block of plaintext (or, indeed a secret key).
This is just a naming mistake of Sun/Oracle.
If so, I would expect these transformations to be equivalent and my test above to pass. The same padding has been specified in both, so why the BadPaddingException?
Either way, I would appreciate a layman's explanation of what the difference is.
For similar Stackoverflow questions with more information please see Maarten Bodewes answers to this and this.
The "mode" part of the transformation string has no effect. The problem is different defaults used by different providers. This is unfortunate and very definitely suboptimal. Should we blame Sun/Oracle? I have no opinion beyond being dissatisfied with the result.
OAEP is a fairly complicated construction with two different hash functions as parameters. The Cipher transform string lets you specify one of these, which you have specified as SHA-256. However, the MGF1 function also is parameterized by a hash function which you cannot specify in the cipher transformation string. The Oracle provider defaults to SHA1 whereas the BouncyCastle provider defaults to SHA-256. So, in effect, there is a hidden parameter that is critical for interoperability.
The solution is to specify more fully what these hidden parameters are by supplying an OAEPParameterSpec to the Cipher.init(...) method as in the following example:
Cipher encryptionCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", "BC");
OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1",
MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
encryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpec);
// ...
// ...
// ...
Cipher decryptionCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1",
MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
decryptionCipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParameterSpec);
The first one is effectively a no-op, because those are already the defaults for Bouncycastle.

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).

What is precise name of the following AES-128 algorithm?

I have the following decryption algorithm implemented in Java. Is information "AES128" enough for other people to implement it in other languages or a more accurate definition is required?
// input data
byte[] secretKey = { ... };
byte[] encryptedData = { ... };
// decryption
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(secretKey);
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128, random);
SecretKey sk = keyGen.generateKey();
SecretKeySpec keySpec = new SecretKeySpec(sk.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec IV16 = new IvParameterSpec(keySpec.getEncoded());
cipher.init(Cipher.DECRYPT_MODE, keySpec, IV16);
byte[] decrypted = cipher.doFinal(encryptedData);
The name of the encryption algorithm itself is AES-128. It's being used in the cipher block chaining mode (this describes how to connect the encryption of multiple sequential blocks), with PKCS #5 padding (this describes how to pad messages up to the size of a full block). Other languages might have different techniques for specifying mode and padding.
AES is the algo, and 128bit the key size. I would say it's pretty clear ...
Essential properties of that algorithm are:
AES
128-bit key
CBC blocks
PKCS-5 aka PKCS-7
Also the following custom tactics used:
custom IV generation from a pass phrase used (bad style)
custom key generation from a pass phrase
Changing any point, changes everything: bytes generated and decryption code.

is AES key random?

AES key may be generate by this code
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
but
If I have a "very reliable" method of generating random numbers can I use it in such a way
SecureRandom rnd = new SecureRandom();
byte[] key = new byte[16];
rnd.nextBytes(key);
is key obtained by this method reliable ?
or it ONLY must generated by some SPECIAL algorithm
The AES key can be any 128 bits. It should be be practically unguessable, whatever the method of creating it.
For Example:
SecureRandom sr = new SecureRandom()
key = new byte[16];
iv = new byte[16];
sr.nextBytes(key);
sr.nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(IV));
SecretKeySpec, by the way, is just a thin wrapper around a byte[] --- it does not transform the key in any way. No "special algorithm".
To add to the other answers ... I believe that the reason that the basic Random functions aren't secure are two reasons:
Slight statistical biases that are acceptable for non-security related situations, but narrow the distributions unacceptably for security applications.
They are seeded by the system DATETIME. Even knowing WHEN you generated your key - to a poor accuracy of +/- 6 months - would significantly reduce the brute force search space.
You can add a random algorithm using SecureRandom :
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random
keyGen.init(random);
SecretKey secretKey = keyGen.generateKey();
It sounds like you're trying to generate an AES key based on a password.
If this is the case, you can use javax.crypto.SecretKeyFactory's generateSecret method, passing in a javax.crypto.spec.PBEKeySpec as the parameter. The PBEKeySpec allows to to specify the password as an argument to its constructor.

Decrypt Blowfish in Java (Generating a secret key in program)

My professor gave us a decryption assignment in which we were given a list of "encrypted" phrases and told to decrypt them. One of them is in blowfish. Me and one of my classmates have tried all the possible keys that he might use. Thus I was going to make a program in Java that would go through all possible keys decrypt the string and then write the decrypted message out to a file. Only problem is all the online tutorials that i can find on writing blowfish in Java have this interface SecretKey being read in from a file.
My question is how do you generate a SecretKey in a program?
This might help you:
byte[] key = getKey();
Cipher cipher = Cipher.getInstance("Blowfish");
SecretKeySpec keySpec = new SecretKeySpec(key, "Blowfish");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
Here's the API you want to use. http://download.oracle.com/javase/6/docs/api/javax/crypto/spec/SecretKeySpec.html#SecretKeySpec%28byte%5b%5d,%20java.lang.String%29
Use a SecretKeySpec to generate a SecretKey using SecretKeyFactory.generate().

Categories

Resources