I am a new bee to Java Security and Crypto. Below code does not return me the correct decryption.
Also please let me know any recommendation for using an algorithm to make a strong key.
Below code has two methods one is for encryption a String and the other is for decryption.
public class TestSecurityDiscussions {
public static byte[] encryptData(KeyPair keys){
String rawData = "Hi how are you>?";
Cipher cipher = Cipher.getInstance("RSA");
try {
cipher.init(Cipher.ENCRYPT_MODE, keys.getPublic());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encrypted = cipher.doFinal(rawData.getBytes());
return encrypted;
}
public static String decryptData(byte[] encrypted,KeyPair keys) {
Cipher cipher = Cipher.getInstance("RSA");
try {
cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
} catch (Exception e) {
e.printStackTrace();
}
byte[] deycrypted = cipher.doFinal(encrypted);
return deycrypted.toString();
}
public static void main(String[] args) {
KeyPair keys = KeyPairGenerator.getInstance("RSA").generateKeyPair();
byte[] keydata = encryptData(keys);
System.out.println("======>"+decryptData(keydata,keys));
}
}
I think your problem is this line:
return decrypted.toString();
Byte Strings will give a memory location via the toString(). You should do this:
return new String(decrypted);
Related
I'm new to Java and encryption. I'm tying to figure out how to decrypt a base64 string using a 36bit GUID string as the secret. As I understand it, I need to convert the GUID passphrase into a 256bit key in order for this to work? Could someone point me in the right direction on how to do this? I've tried some standard AES decryption code like the below but I get a javax.crypto.BadPaddingException: Given final block not properly padded error.
public static String decrypt(String strToDecrypt, String secret)
{
try
{
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)), "UTF-8");
}
catch (Exception e)
{
System.out.println("Error while decrypting: " + e.toString());
}
return null;
}
public static void setKey(String myKey)
{
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
UPDATE
So after more digging the string is encrypted using the crypto-js library with the default AES encryption function. This question has an example to decrypt this and a good explanation of how crypto-js encrypts with AES.
I have facing issue after applying encryption into a string, I want to decrypt that encrypted_string to a normal string, But none of the examples is working.
Also, they are working for byte array code, Byte_array encrypted and decrypted very well, But I need this working for the string.
Example, I tried already,
How to encrypt and decrypt String with my passphrase in Java (Pc not mobile platform)?
public static String encrypt(String strClearText,String strKey) throws Exception{
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted=cipher.doFinal(strClearText.getBytes());
strData=new String(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
public static String decrypt(String strEncrypted,String strKey) throws Exception{
String strData="";
try {
SecretKeySpec skeyspec=new SecretKeySpec(strKey.getBytes(),"Blowfish");
Cipher cipher=Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted=cipher.doFinal(strEncrypted.getBytes());
strData=new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
String to byte[] then byte[] to string conversion not working properly?
You can use Base64 enocde and decode.
Example:
package test;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Test2 {
public static void main(String[] args) throws Exception {
String key = "abc123!";
String encrypted = encrypt("test", key);
System.out.println(encrypted);
String decrypted = decrypt(encrypted, key);
System.out.println(decrypted);
}
public static String encrypt(String strClearText, String strKey) throws Exception {
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted = cipher.doFinal(Base64.getDecoder().decode(strClearText));
strData = Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
public static String decrypt(String strEncrypted, String strKey) throws Exception {
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec(strKey.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(strEncrypted));
strData = Base64.getEncoder().encodeToString(decrypted);
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e);
}
return strData;
}
}
Output:
Fsmwp8c1n9w=
test
Here simple encoding and decoding (above kitkat)
Write this class and just call method
class EncodeDecode
{
public String encodeString(String text)
{
String b64;
byte[] data=new byte[0];
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
{
data=text.getBytes(StandardCharsets.UTF_8);
b64=Base64.encodeToString(data,Base64.DEFAULT);
}
return b64;
}
public String decodeString(String text)
{
String deString;
if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT)
{
byte[] data2=Base64.decode(base64,Base64.DEFAULT);
deString=new String (data2,StandardCharsets.UTF_8);
}
return deString;
}
}
I hope this answer will help you..
CipherText
i5SvmG2TbtZfkWdwJ5qeaYzvLlQknY3uMvZxSEwhBdRcXKHjgzrRk6XLDCEG9ZtZDGDA7iB3tFhLPMisfqGZvSSrcBfiV8b71+qzWVDNW9EedVShk6kaeEN6rw4UgVi6P5PvrDMn6pmYmLWCjtuFWrmboCvvYgI+FJurhlbsQESkA5oDYirjS8L0wnsQB/TnnQ5UPY2xfOBdY2MJpUSTyIjJPhI40GST8YWjXEMkJeDV/1zuKuK55RHCDF5AdTMEvgvvRnGhN2Fzh+rsDziHqVS9d8FmrtjdU445F6ki0d8DkaeFfrofptxGIncqfuukKSXpSp4cPLvM3LxtRvp+Aw==
Code to decrypt
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp2 = kpg.generateKeyPair();
generatedPub = kp2.getPublic();
generatedPvt = kp2.getPrivate();
public String rsaDecrypt(String encrypted) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, generatedPvt);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted.getBytes()));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Error
javax.crypto.BadPaddingException: error:04000089:RSA routines:OPENSSL_internal:PKCS_DECODING_ERROR
Also, if I try printing the private key as :
generatedPvt.toString()
I get the following :
OpenSSLRSAPrivateCrtKey{modulus=c7544bf521bbdd7db52dd28bd3c6f694214dc2356b905edd2730b631d11be9aea703692c2db690e6725da65737b5ec511c13668d1735bfbbc2519e0d33a67b41b289bae6ea71903af91e4f12c6e8660614ef12cd439293a0a38f564fd8f19a3e38f9e2defa269d0bcf0f53159bba1b4fd539ad934fb691e860113be53901de5a10d0c0e3ceaec3715841bc6e56b7738336e8df95a989b61175b06d70d349dcb4a031acf5b25647a1d77f6e6e11efc66e98bb321430f148a63c103a0a59e94b147a4fb49a9ecb0b23603a6ceed6e6e298650667cd61de71455bd4f95767444d89bcf485cc47a297b5306a60a14f77a3fbc19552c5fddfa5cfa2e68020e245ad91,publicExponent=10001}
While I was expecting the PKCS#8 formatted key to be printed. How do i get the key printed in the PKCS#8 format ?
And why am i getting the padding error as shown above ?
byte[] original = cipher.doFinal(encrypted.getBytes());
remove Base64.decodeBase64 from both encrypt and decrypt methods
if you want to convert key to string then use
String keyString= Base64.encodeBase64String(key.getEncoded());
RSA Implementation
public static void main(String[] args) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp2 = kpg.generateKeyPair();
PublicKey publicKey = kp2.getPublic();
PrivateKey privateKey = kp2.getPrivate();
NewClass nc = new NewClass();
byte[] encrypt=nc.rsaEncrypt("hi",publicKey);
byte[] decrypt=nc.rsaDecrypt(encrypt,privateKey);
String decryptString = new String(decrypt);
System.out.println("decryptString = " + decryptString);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
public byte[] rsaDecrypt(byte[] encrypted,PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] original = cipher.doFinal(encrypted);
return original;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public byte[] rsaEncrypt(String message,PublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] original = cipher.doFinal(message.getBytes());
return original;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
When encoding and decoding is done along with encrypt and decrypt the order must be
Encryption
cipher.doFinal(Base64.encodeBase64(message.getBytes()));
Decryption
Base64.decodeBase64(cipher.doFinal(cipher.getBytes()));
I'm trying to save few text fields securely. For that I'm trying to encrypt and decrypt the content. This is the code:
public class SecureStorage {
public String getPassword() {
if(!isRooted()) {
String password = pref.getPassword("");
System.out.println("pass getPass: " + password);
return password.isEmpty() ? password : new String(decrypt(Base64.decode(password, Base64.DEFAULT)));
} else
return "";
}
public void setPassword(String passwordStr) {
if(!isRooted()) {
byte[] password = encrypt(passwordStr.getBytes());
pref.setPassword(password == null ? "" : Base64.encodeToString(password, Base64.DEFAULT));
}
}
private SecretKey generateKey() {
// Generate a 256-bit key
final int outputKeyLength = 256;
try {
SecureRandom secureRandom = new SecureRandom();
// Do *not* seed secureRandom! Automatically seeded from system entropy.
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(outputKeyLength, secureRandom);
return keyGenerator.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private byte[] getRawKey(byte[] key) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "Crypto");
secureRandom.setSeed(key);
keyGenerator.init(128, secureRandom); // 192 and 256 bits may not be available
SecretKey secretKey = keyGenerator.generateKey();
byte[] rawKey = secretKey.getEncoded();
return rawKey;
}
/** The method that encrypts the string.
#param toEncrypt The string to be encrypted.
#return The encrypted string in bytes. */
//****************************************
private byte[] encrypt(byte[] toEncrypt) {
byte[] encryptedByte = new String().getBytes();
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
encryptedByte = cipher.doFinal(toEncrypt);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return encryptedByte;
}
//**************************************
/** The method that decrypts the string.
#param encryptedByte The string to be encrypted.
#return The decrypted string in bytes. */
//****************************************
private byte[] decrypt(byte[] encryptedByte) {
byte[] decryptedByte = new String().getBytes();
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
decryptedByte = cipher.doFinal(encryptedByte);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return decryptedByte;
}
}
I'm able to encrypt the Text.
I'm using SharedPreferences to store the encrypted text and getting the sharedprefs to decrypt the text and give it to a TextView. But in the getPassword() I'm getting the SharedPreference value and trying to decrypt if there is any value in the SharedPrefs. I'm getting the SharedPrefs into a string (password) and trying to decrypt it, but I'm unable to! I'm getting an empty String!
CBC mode needs an initialization vector (IV) in order to operate. The IV is there to randomize the ciphertext and prevent an attacker from determining whether previous plaintexts had the same prefix as the current one.
Since you're not generating any IV, it will be generated for you. A wrong IV only affects the first block (first 16 bytes for AES). If your plaintext is shorter than a block, then this will lead to completely different decryption and then the padding cannot be removed with a probability of roughly 255/256.
The IV is not supposed to be secret. It is common to prepend it to the ciphertext and slice it off before decryption.
public byte[] encrypt(byte[] toEncrypt) throws Exception {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] iv = cipher.getIV();
byte[] ct = cipher.doFinal(toEncrypt);
byte[] result = new byte[ct.length + iv.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(ct, 0, result, iv.length, ct.length);
return result;
} catch(...) {...}
return new byte[0];
}
public byte[] decrypt(byte[] encryptedByte) throws Exception {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
byte[] ct = new byte[encryptedByte.length - cipher.getBlockSize()];
System.arraycopy(encryptedByte, 0, iv, 0, cipher.getBlockSize());
System.arraycopy(encryptedByte, cipher.getBlockSize(), ct, 0, ct.length);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));
return cipher.doFinal(ct);
} catch (...) {...}
return new byte[0];
}
The problem with this might be that the ciphertext is bigger than anticipated (16 bytes additionally for the IV). If you can make sure that an attacker doesn't get any useful information from determining that previous plaintexts had the same prefix, then you could use a static IV. But be aware that this is usually not that great of an idea and should only be done if you really need that space.
private static final byte[] IV = new byte[16];
...
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(IV));
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV));
I have written my program in java by following this tutorial http://www.java2s.com/Code/Android/Security/AESEncryption.htm
But i am getting an exception i.e. "javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"
Can anybody help me?
public class utils {
public static String encrypt(String message,String secretPhrase){
try{
MessageDigest mdig=MessageDigest.getInstance("MD5");
byte[] digestedBytes=mdig.digest(secretPhrase.getBytes("UTF-8"));
SecretKeySpec keySpec=new SecretKeySpec(digestedBytes,"AES");
Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes=cipher.doFinal(message.getBytes("UTF-8"));
return new String(encryptedBytes,"UTF-8");
}catch(Exception exc){
return null;
}
}
public static String decrypt(String message,String secretPhrase){
try{
MessageDigest mdig=MessageDigest.getInstance("MD5");
byte[] digestedBytes=mdig.digest(secretPhrase.getBytes("UTF-8"));
SecretKeySpec keySpec=new SecretKeySpec(digestedBytes,"AES");
Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] encryptedBytes=cipher.doFinal(message.getBytes("UTF-8"));
return new String(encryptedBytes,"UTF-8");
}catch(Exception exc){
return null;
}
}
}
Well try this ,
public String encrypt(String str) {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
} catch (Exception e) {
}
return null;
}
public String decrypt(String str) {
try {
// Decode base64 to get bytes
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (Exception e) {
}
return null;
}
Example using it
try {
// Generate a temporary key. In practice, you would save this key.
// See also Encrypting with DES Using a Pass Phrase.
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
// Create encrypter/decrypter class
DesEncrypter encrypter = new DesEncrypter(key);
// Encrypt
String encrypted = encrypter.encrypt("Don't tell anybody!");
// Decrypt
String decrypted = encrypter.decrypt(encrypted);
} catch (Exception e) {
}