I got an encrypting key in HEX format and its intialization vector (HEX), the length of both of them is 32, I got an encrypted phone number from the client side, and I should decrypt it using the same encryption key.
Here is the method:
private static final String key = "*";
private static final String initVector = "*";
private static final String characterEncoding = "UTF-8";
private static final String cipherTransformation = "AES/CBC/PKCS5PADDING";
private static final String aesEncryptionAlgorithem = "AES";
public static String decrypt(String encryptedText) {
String decryptedText = "";
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
byte[] keyByte = key..getBytes(characterEncoding);
SecretKeySpec secretKey = new SecretKeySpec(keyByte, aesEncryptionAlgorithem);
IvParameterSpec ivparameterspec = new IvParameterSpec(initVector.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
Base64.Decoder decoder = Base64.getDecoder();
byte[] cipherText = decoder.decode(encryptedText.getBytes("UTF8"));
decryptedText = new String(cipher.doFinal(cipherText), "UTF-8");
} catch (Exception E) {
System.err.println("decrypt Exception : "+E.getMessage());
}
return decryptedText;
}
the length of the given key and Iv is 32, I got this exception:
Encrypt Exception : Wrong IV length: must be 16 bytes long
I think I should convert the key and the Iv to another format in order to have the wanted length.
Related
I have got this code from Server guys:
public string Encryption(string PlainText)
{
string key = "twelve_digit_key";
TripleDES des = CreateDES(key);
ICryptoTransform ct = des.CreateEncryptor();
byte[] input = Encoding.Unicode.GetBytes(PlainText);
byte[] buffer = ct.TransformFinalBlock(input, 0, input.Length);
return Convert.ToBase64String(buffer);
}
static TripleDES CreateDES(string key)
{
MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
des.IV = new byte[des.BlockSize / 8];
return des;
}
This is my code against above :
public String encryptDES(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(getNativeKey3().getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; ) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(digestOfPassword, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
return Base64.encodeToString(cipherText, Base64.DEFAULT)
.replace("\n", "")
.replace("\r", "");
}
Problem :
First Code gives below result :
Encrypted Text for 121212 is VvRQkSUj5SQ69mGXsL+h6w==
But Second Code returns this :
Encrypted Text for 121212 is 2STVJSd1mnw=
Observations :
When I increase the plainttext to 10 digits I am getting 24 digit cipher text
Can any one help me in this:
Thanks in Advance
You've been fooled by the badly named Unicode class, which actually specifies UTF-16LE rather than UTF-8.
You can use StandardCharsets.UTF_16LE for specifying the encoding rather than the string; this saves you from one exception to handle.
If there are still issues with the length (test!) then you may have to deal with the Byte Order Mark or BOM - but I don't think so.
I am trying to write an encryption/decryption utility class, but not matter what I do I cannot seem to get decryption working. I keep getting a javax.crypto.BadPaddingException: Given final block not properly padded exception during decryption.
I've looked at a number of examples and other stack overflow questions but can't seem to find my mistake
public class EncryptionUtil {
private static final Log LOGGER = LogFactory.getLog(EncryptionUtil.class);
private static final String CIPHER_MODE = "AES/CBC/PKCS5PADDING";
private static final String CRYPTO_PROPERTIES_PATH = "/crypto.properties";
private static final SecretKeySpec sKey = keySpecFromProperties();
private EncryptionUtil() {}
public static byte[] encrypt(byte[] aBytes) {
try {
SecureRandom lSecureRandom = new SecureRandom();
byte[] ivBytes = new byte[16];
lSecureRandom.nextBytes(ivBytes);
IvParameterSpec lSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.ENCRYPT_MODE, sKey, lSpec);
byte[] encryptedBytes = cipher.doFinal(aBytes);
byte[] outBytes = new byte[encryptedBytes.length + 16];
System.arraycopy(ivBytes, 0, outBytes, 0, 16);
System.arraycopy(encryptedBytes, 0, outBytes, 16, encryptedBytes.length);
return outBytes;
} catch (Exception aEx) {
LOGGER.error("Failed to encrypt bytes");
throw new RuntimeException(aEx);
}
}
public static byte[] decrypt(byte[] aBytes) {
try {
byte[] lIvBytes = Arrays.copyOfRange(aBytes, aBytes.length - 16, aBytes.length);
byte[] lEncryptedBytes = Arrays.copyOfRange(aBytes, 0, aBytes.length - 16);
IvParameterSpec lIvSpec = new IvParameterSpec(lIvBytes);
Cipher cipher = Cipher.getInstance(CIPHER_MODE);
cipher.init(Cipher.DECRYPT_MODE, sKey, lIvSpec);
return cipher.doFinal(lEncryptedBytes);
}catch (Exception aEx){
LOGGER.error("Failed to decrypt bytes. Returning input bytes", aEx);
return aBytes;
}
}
private static SecretKeySpec keySpecFromProperties(){
try(InputStream lPropStream = EncryptionUtil.class.getResourceAsStream(CRYPTO_PROPERTIES_PATH)){
Properties cryptoProps = new Properties();
cryptoProps.load(lPropStream);
String lSecret = cryptoProps.getProperty("secret");
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(lSecret.getBytes("UTF-8"));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(),0, keyBytes, 0, keyBytes.length);
return new SecretKeySpec(keyBytes, "AES");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
You prepend your IV to the ciphertext on encryption, but on decryption you copy the last 16 bytes as your IV.
Whatever you do on encryption you must undo on decryption.
' Encrypts a string using tripple DES
Private Function TripleDESEncrypt(ByVal str As String) As TripleDESEncryptResult
' 3DES Encryption
' Generate KEY/IV pair for your local 3DES encrpytion on xmlCard
' Create a new 3DES CryptoProvider and generate KEY/IV pair for encryption
Dim m_cryptoProvider As New TripleDESCryptoServiceProvider
m_cryptoProvider.GenerateIV()
m_cryptoProvider.GenerateKey()
Dim stream As System.IO.MemoryStream = New System.IO.MemoryStream
Dim cryptoStream As CryptoStream = _
New CryptoStream(stream, m_cryptoProvider.CreateEncryptor, _
CryptoStreamMode.Write)
Dim Input() As Byte = System.Text.Encoding.Default.GetBytes(str)
cryptoStream.Write(Input, 0, Input.Length)
cryptoStream.FlushFinalBlock()
' Convert to base64, so it'll be XML-friendly
Dim encryptedCardString = System.Convert.ToBase64String(stream.ToArray())
cryptoStream.Close()
cryptoStream.Dispose()
Return New TripleDESEncryptResult(encryptedCardString, m_cryptoProvider.Key, m_cryptoProvider.IV)
End Function
Below code is in java for 3DES encryption and decryption. please try with this code. I hope it will help you
private static final String UNICODE_FORMAT = "UTF8";
public static final String DESEDE_ENCRYPTION_SCHEME = "DESede"; //"DESede/ECB/NoPadding";
private KeySpec ks;
private SecretKeyFactory skf;
private Cipher cipher;
byte[] arrayBytes;
private String myEncryptionKey;
private String myEncryptionScheme;
SecretKey key;
public PasswordEncryption_TrippleDES() throws Exception {
myEncryptionKey = "ThisIsSpartaThisIsanilku";
myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME;
arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
ks = new DESedeKeySpec(arrayBytes);
skf = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = skf.generateSecret(ks);
}
public String encrypt(String unencryptedString) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = new String(Base64.encodeBase64(encryptedText));
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
public String decrypt(String encryptedString) {
String decryptedText=null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = Base64.decodeBase64(encryptedString);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText= new String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
public static void main(String args []) throws Exception
{
PasswordEncryption_TrippleDES td= new PasswordEncryption_TrippleDES();
String target="data for encyption";
String encrypted=td.encrypt(target);
String decrypted=td.decrypt(encrypted);
System.out.println("String To Encrypt: "+ target);
System.out.println("Encrypted String:" + encrypted);
System.out.println("Decrypted String:" + decrypted);
}
I setup a program for a class I am taking on crypto. I will follow this with my code and another section for my variable differences. My goal is to decrypt the text for our homework. I do not want someone to decrypt this for me, but would like some help as to what is causing this within my code. When I decrypt CBC I get the correct output with no problem, though it does have some extra chars in it (this may be an issue with padding? I am not sure)
Then when I use the CTR with the correct changes it returns a bunch of garbage. Any help would be greatly appreciated.
Thank you,
CBC:
CBC key: 140b41b22a29beb4061bda66b6747e14
CBC Ciphertext 1:
4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81
CTR:
CTR key: 36f18357be4dbd77f050515c73fcf9f2
CTR Ciphertext 1:
69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329
CBC Variables
String algorithm = "AES";
String mode = "CBC";
String padding = "PKCS5Padding";
byte[] ciphertextBytes = StringToByte("4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81");
byte[] keyBytes = StringToByte("140b41b22a29beb4061bda66b6747e14");
CTR Variables
String algorithm = "AES";
String mode = "CTR";
String padding = "NoPadding";
byte[] ciphertextBytes = StringToByte("770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451");
byte[] keyBytes = StringToByte("36f18357be4dbd77f050515c73fcf9f2");
Decrypt Main
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import static java.lang.Character.digit;
public class CryptoClass {
public static void main(String[] args) throws Exception {
byte[] decryptByte = Decrypt();
String hexString = ByteToHex(decryptByte);
StringBuilder decryptedString = HexToString(hexString);
System.out.println(decryptedString);
}
public static byte[] Decrypt() throws Exception {
//
String algorithm = "AES";
String mode = "CTR";
String padding = "NoPadding";
byte[] ciphertextBytes = StringToByte("770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451");
byte[] keyBytes = StringToByte("36f18357be4dbd77f050515c73fcf9f2");
IvParameterSpec ivParamSpec = null;
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.nextBytes(iv);
ivParamSpec = new IvParameterSpec(iv);
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + padding, "JsafeJCE");
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParamSpec);
byte[] result = cipher.doFinal(ciphertextBytes);
return result;
}
//convert ByteArray to Hex String
public static String ByteToHex(byte[] byteArray) {
StringBuilder sb = new StringBuilder();
for (byte b : byteArray)
{
sb.append(String.format("%02X", b));
}
return sb.toString();
}
//convert String to ByteArray
private static byte[] StringToByte(String input) {
int length = input.length();
byte[] output = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
output[i / 2] = (byte) ((digit(input.charAt(i), 16) << 4) | digit(input.charAt(i+1), 16));
}
return output;
}
//changes a hex string into plain text
public static StringBuilder HexToString(String hex) throws Exception {
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
return output;
}
}
*Edit method for solution - instead of a random IV I pulled the IV from the first 16 bits of the ciphertext. In the assignment it stated that this was the case, for some reason I glossed over it when I looked through it the first time.
public static byte[] Decrypt() throws Exception {
String algorithm = "AES";
String mode = "CTR";
String padding = "NoPadding";
byte[] ciphertextBytes = StringToByte("0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329");
byte[] keyBytes = StringToByte("36f18357be4dbd77f050515c73fcf9f2");
//int ivSize = 16;
//byte[] iv = new byte[ivSize];
//SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
//secureRandom.nextBytes(iv);
byte[] ivParamSpecTMP = StringToByte("69dda8455c7dd4254bf353b773304eec");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivParamSpecTMP);
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + padding, "JsafeJCE");
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
byte[] result = cipher.doFinal(ciphertextBytes);
return result;
The trick is that you must send the IV (in plain text) to the receiver. If you randomly generate the IV before decryption you will get garbage by definition. Random IV's should only be generated before encryption.
Standard practice is for the sender to prefix the IV to the ciphertext. The receiver uses the first 16 bytes as an IV and the rest as the actual ciphertext.
I am using this class to encrypt a string in android app
public class Encryption {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
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;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
}
I am using above class like this -
Encryption.encrypt("password", "some text to be encrypted");
Their is no problem in encrypting the string, but when i try to decrypt the encrypted string (using the same class i posted above) in external java program (not in android app),
Encryption.decrypt("password","D4036388D459C4009812FB3F1AE4BB36E4419C97775D");
i get this exception -
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at Encryption.decrypt(Encryption.java:59)
at Encryption.decrypt(Encryption.java:32)
at Encryption.main(Encryption.java:96)
I think, this is because i am using same code on different platforms,
But i don't know proper reason why this doesn't work ? and
Is their any way i can decrypt the string in java?
#SteveP is probably right.
Still another problem I see, is the byte[] getBytes("UTF-8") (binary data) to String new String(bytes, "UTF-8") (text) conversion. On Android the default encoding is UTF-8, on Windows most likely something else.