I would like to know how i could decipher a random number DES/CBC-enciphered with a specific Key.
My protocol states the following:
I am sending a KeyNo (eg. 0x00)
After the KeyNo is sent i get a 8byte (DES) random number. This random number is enciphered with the selected key.
My question would be how do i decipher the data i receive, to find the random number using Cipher
Thank you.
To decrypt a DES encrypted stream, simply do :
Key key = SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(bytesOfThe Key)); // bytesOfTheKey should be 8 bytes long
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
return new CipherInputStream(inputStream, cipher);
You may also be interested in the doFinal method which works on byteBuffers.
Related
I'm developping an Android app and i wanna do encryption with AES-128.
I use secret key and text with hexadecimal.
I use this website : http://testprotect.com/appendix/AEScalc to compute the AES encryption with the following key : "c4dcc3c6ce0acaec4327b6098260b0be" and my text to encrypt is : "6F4B1B252A5F0C3F2992E1A65E56E5B8" (hexadecimal).
So the result from this website give me "859499d0802de8cc6ba4f208da648a8f" and that's the result i wanna get.
http://hpics.li/d89105a
I find some code on the net, but a lot uses seed to generate random secret key and i wanna fix the secret key.
Actually i'm using the following code, i think it's the code i need but the result gives me D/resultdebug: 72adc67b6d11e1c5fb89ddf5faeb0e030686b91f8bfaf6c41335f08955343f87
and it's not the same result than the website, that i want.
String text16 = "6F4B1B252A5F0C3F2992E1A65E56E5B8";
String secret16 = "c4dcc3c6ce0acaec4327b6098260b0be";
SecretKeySpec sks = new SecretKeySpec(secret16.getBytes(),"AES");
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, sks);
c.update(text16.getBytes());
byte[] ciphertext = c.doFinal();
Log.d("resultdebug",new String(Hex.encode(ciphertext), "ASCII"));
Could you please tell me what's wrong, thanks.
You are not converting the hex to binary, you are getting the binary of the characters not the value that is hex encoded.
Thanks zaph, it solved my problem
I added these two lines on my code :
byte[] text = stringhextobyte(text16);
byte[] secret = stringhextobyte(secret16);
And the function stringhextobyte permit me to transform my hex string to byte array and i get the result needed.
Im new to cryptography in Java and I am trying to write a program to encrypt and decrypt a phrase using DES symmetric cipher, based on CBC mode of operation.
Can anyone tell me how to go about creating an 8-byte initialization vector and how to cast the new IV into AlgorithmParameterSpec class?
Also, which packages should I import?
Edit: Right now I have these lines:SecureRandom sr = new SecureRandom(); //create new secure random
byte [] iv = new byte[8]; //create an array of 8 bytes
sr.nextBytes(iv); //create random bytes to be used for the IV (?) Not too sure.
IvParameterSpec IV = new IvParameterSpec(iv); //creating the IV
Is my above approach correct?
Thanks.
Yes. Till Now You are right.
the Class IvParameterSpec is used to pass Initial Vector to Class Cipher
After this create a Cipher as below
Cipher cipherInstance = Cipher.getInstance("DES/CBC/NoPadding");
here DES/CBC/NoPadding is used because you are useing DES encryption in CBC mode.
Next is initializing it.
cipherInstance.init(Cipher.DECRYPT_MODE, Key, ivParameterSpec);
Parameters are:
1st is mode of encryption either Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
2nd is Secret Key You have generated using Class SecretKey
3rd is generated ivParameterSpec
and last line is
outData = cipherInstance.doFinal(input);
if mode is Decrypt it will return decrypted data and if mode is Encrypt it will return encrypted data.
Last but important catch all the Exceptions properly.
And you are done
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.
I have web services implemented that comunicate between client and server with strings. The problem I'm getting is with the conversion of the encripted byte array to string since I can't convert it back to the original content on server side.
KeyPairGenerator keyGen;
keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair key = keyGen.generateKeyPair();
String publicKeyPath = new String("publicKeys.txt");
publickey = key.getPublic()
byte[] pubEncoded = key.getPublic().getEncoded();
FileOutputStream fout = new FileOutputStream(publicKeyPath);
fout.write(pubEncoded);
fout.flush();
fout.close();
String privateKeyPath = new String("privateKeys.txt");
byte[] privEncoded = key.getPrivate().getEncoded();
fout = new FileOutputStream(privateKeyPath);
fout.write(privEncoded);
fout.flush();
fout.close();
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
And on each method in client:
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publickey);
byte[] cipherText = cipher.doFinal(str.getBytes());
port.callX(chiperText.toString());
On server side:
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] newPlainText = cipher.doFinal(arg.getBytes());
This gives the padding problem of "Data must start with a zero"
There is only one KeyPair generated, for debug, I tried to encrypt and decript on the same function, and the problem relies on the conversions from byte[] to String.
I don't really wan't to change the passing of arguments to other type since operations are auto generated and all code is to strings. I've tried with different "UTF-8" and "UTF-16Le" but none works :S
Any idea?
Encrypting data directly with asymmetric keys isnt a good idea and it does not work. RSA keys cannot encrypt data bigger than its key length. So, the right way of doing that would be to generate a symmetric key and encrypt the data with the symmetric key and inturn encrypt the symmetric key with the asymmetric key. So, you need to send the encrypted data and the encrypted key both to the other party.
If you try encrypting the data directly with the asymmetric key then your byte[] may not contain the correct data or it may contain nothing at all. This happens if your data is bigger than the key length. For data smaller the key length it works fine but not with bigger data.
So basically I have these snippets of code and would like them to produce the same output:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
aes.encrypt
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
This prints:
8d3bbffade308f8e4e80cb77ecb8df19ee933f75438cec1315c4a491bd1b83f4
And this Java code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String key = "aaaaaaaaaaaaaaaa";
String textToEncryptpt = "1234567890123456";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(textToEncryptpt.getBytes());
System.out.println(Crypto.bytesToHex(encrypted));
Prints:
2d3760f53b8b3dee722aed83224f418f9dd70e089ecfe9dc689147cfe0927ddb
Annoying thing is that it was working a couple of days ago... so I am not sure what happened. What's wrong with this code? Do you see anything unusual?
Ruby script is wrong. You have to first call the encrypt method, and then set the key and iv:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.encrypt
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
I figured out because when trying to decode an encrypted string I got:
aescrypt.rb:13:in `final': bad decrypt (OpenSSL::Cipher::CipherError)
from aescrypt.rb:13:in `<main>'
Seems you found already the reason that your script does give different results.
Some more things to consider:
Don't ever hardcode the key in the program - that way you can't easily change it, and if someone gets access to your program code, she also gets to see the key.
Don't ever use a constant initialization vector. Instead, generate a random one and send it together with the ciphertext. Alternatively, if you generate the key from a password and some salt, you can also generate the IV from the same ... but don't use the key directly as IV.
Your key/IV values are strings, not bytes. String.getBytes() (in Java) converts the string to bytes using some encoding. The encoding used is system-dependent, and none of the usual String encodings (UTF-8, Latin-1, ...) can represent all bytes as printable (and typeable) characters. Preferably use something like Base64 or hex-encoding, if you have to store your key as string.
And whenever you transform a string to bytes, specify an encoding (and use the same encoding later for retrieving it).
#Cristian, For key and initial vector, you can create a function by using today's date plus the secure fixed keyword.
Eg: key = January 8, 2012 + Key
And for initial vector,
Eg: iv = January 8, 2012 + IV
Then enter that data(key and iv) to MD5 it will produce the output 16 bytes that you can use for the Key and IV. Every day, key and iv will change randomly.
Make sure both systems use the same date format and setup on the same date.