Code:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class crypto {
public static void main(String [] args) {
String s = args[0];
String s1 = args[1];
String ivkey = "thisisasecretword1";
byte[] ivraw = ivkey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(ivraw, "AES");
byte[] iv = { 't','h','i','s','a','s','e','c','r','e','t','w','o','r','d','1' };
IvParameterSpec ivspec = new IvParameterSpec(iv);
if (s.equalsIgnoreCase("ENCRYPT")) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
byte[] encrypted = cipher.doFinal(s1.getBytes());
System.out.println("encrypt: " + new String(Base64.encodeBase64(encrypted)));
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
byte[] encrypted = cipher.doFinal(Base64.decodeBase64(s1));
System.out.println("decrypt: " + new String(encrypted));
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
I'm trying to compile this just to test the new encryption methods that we're thinking of using. This is the first iteration but will be dutifully secured at a later date to implement a randomized key. Anyway, when I try to compile this I set my classpath in osx to the location where the commons-coded-1.9.jar is located. I run javac crypto.java and no errors. I run java crypto "ENCRYPT" "TEST" and just get a NoClassDefFoundError: crypto message. I've been screwing with this but can't see where I made the mistake. Hopefully a fresh pair of eyes will be able to shine some light on it.
Related
I am unable to decrypt data on iOS(Swift) which I am getting from the Java server. But if I encrypt a data on iOS and then decrypt, it works well. There might be some variance on both side's AES code which I am not able to identify. Please help me.
Similar question asked here: https://github.com/krzyzanowskim/CryptoSwift/issues/458
iOS Decryptor
let password = "SOME_ENCRYPTION_KEY"
let iv = AES256Crypter.randomIv()
let key = try AES256Crypter.createKey(password: password.data(using: .utf8)!, salt: salt)
let aes = try AES256Crypter(key: key, iv: iv)
let encryptedData = "encrypted_data".data(using: .utf8)
let decryptedData = try aes.decrypt(encryptedData!)
let decryptedString = String(decoding: decryptedData, as: UTF8.self)
print("Decrypted string: \(decryptedString)")
Java Encryptor
SecretKeySpec secretKey;
try {
byte[] key = ENCRYPTION_KEY.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
} catch (Exception e) {
System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
}
Below is the code for Encryption in Java
and Decryption for iOS(Swift and Android(Kotlin). This works well but I am still open for a better solution.
Java Code
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class EncryptionUtils {
private static String ENCRYPTION_KEY = "1234512345123456";
public static void main(String[] args) {
String encyString = new EncryptionUtils().encrypted("HJUSER153");
System.out.println("Encrypted String:" + encyString);
}
public String encrypted(String strToEncrypt) {
try {
IvParameterSpec ivspec = new IvParameterSpec(ENCRYPTION_KEY.getBytes());
SecretKeySpec keyspec = new SecretKeySpec(ENCRYPTION_KEY.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
//encrypted = cipher.doFinal(text.getBytes());
} catch (Exception e) {
System.out.println("\nException while encrypting " + strToEncrypt + " \nerror: " + e.getMessage());
}
return null;
}
}
iOS Swift Code
Add this in pod file -
pod 'CryptoSwift'
import CryptoSwift
func decrypt(input:String)->String?{
let key = "1234512345123456"
do{
let d=Data(base64Encoded: input)
let decrypted = try AES(key: key, iv: key, padding: .pkcs5).decrypt(
d!.bytes)
return String(data: Data(decrypted), encoding: .utf8)
}catch{
}
return nil
}
Android
import android.util.Base64
import java.security.NoSuchAlgorithmException
import javax.crypto.Cipher
import javax.crypto.NoSuchPaddingException
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
class CypherHelper {
private var ivspec: IvParameterSpec? = null
private var keyspec: SecretKeySpec? = null
private var cipher: Cipher? = null
private val ENCRYPTION_KEY: String = "1234567890123456"
init {
ivspec = IvParameterSpec(ENCRYPTION_KEY.toByteArray(Charsets.UTF_8))
keyspec = SecretKeySpec(ENCRYPTION_KEY.toByteArray(), "AES")
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: NoSuchPaddingException) {
e.printStackTrace()
}
}
fun decrypt(valueToDecrypt: String): String {
var decryptValue: String = ""
val enc = CypherHelper()
if (valueToDecrypt.isEmpty())
decryptValue = String(enc.decryptInternal(valueToDecrypt)!!)
return decryptValue
}
private fun decryptInternal(code: String?): ByteArray? {
if (code == null || code.isEmpty()) {
throw Exception("Empty string")
}
var decrypted: ByteArray? = null
try {
cipher?.init(Cipher.DECRYPT_MODE, keyspec, ivspec)
decrypted = cipher?.doFinal(Base64.decode(code, Base64.DEFAULT))
} catch (e: Exception) {
throw Exception("[decrypt] " + e.message)
}
return decrypted
}
}
I'm getting this error when I try to decrypt a message which has already been encrypted.
I've done this by first encrypting a message in this case "Testing message"
Then running the method again but decrypting instead of encrypting.
I've looked at the other questions regarding this but could not fix the problem
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class PBEusing {
public static void main(String[] args) throws Exception {
PBEusing pbe = new PBEusing();
String encrypt = pbe.pbe("encrypt", "passwordTest", "Testing message");
System.out.println(encrypt);
String decrypt = pbe.pbe("decrypt", "passwordTest", encrypt);
System.out.println(decrypt);
}
public static String pbe(String cipherMethod, String clientPassword, String clientMessage) throws Exception {
String method = cipherMethod.toUpperCase();
String output = "";
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[16];
rnd.nextBytes(iv);
byte[] plaintext = clientMessage.getBytes(StandardCharsets.UTF_8); // input message from user
byte[] salt = "01234567".getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 10000, ivParamSpec);
PBEKeySpec keySpec = new PBEKeySpec(clientPassword.toCharArray());
try {
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
SecretKey secretKey = kf.generateSecret(keySpec);
// On J2SE the SecretKeyfactory does not actually generate a key, it just wraps the password.
// The real encryption key is generated later on-the-fly when initializing the cipher
System.out.println(new String(secretKey.getEncoded()));
// Encrypt
if (method.equals("ENCRYPT")) {
Cipher enc = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
enc.init(Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
byte[] encrypted = enc.doFinal(plaintext);
output = new BASE64Encoder().encode(encrypted);
System.out.println("Encrypted text: " + output);
} else {
// Decrypt
Cipher dec = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
dec.init(Cipher.DECRYPT_MODE, secretKey, pbeParamSpec);
byte[] decrypted = dec.doFinal(plaintext);
String test = new BASE64Encoder().encode(decrypted);
//String message = new String(test, StandardCharsets.UTF_8);
output = test;
}
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
}
return output;
}
}
You're Base64 encoding the output of the encryption but aren't Base64 decoding it again before you try to decrypt it.
I've tried to implement IDEA algorithm. here is the code that i found on google:
package ideaalgoritam;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class IDEAalgoritam {
public static void main(String []args) throws Exception {
String toEncrypt = "The shorter you live, the longer you're dead!";
System.out.println("Encrypting...");
byte[] encrypted = encrypt(toEncrypt, "password");
System.out.println("Decrypting...");
String decrypted = decrypt(encrypted, "password");
System.out.println("Decrypted text: " + decrypted);
}
public static byte[] encrypt(String toEncrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance("IDEA");
kg.init(sr);
SecretKey sk = kg.generateKey();
// create an instance of cipher
Cipher cipher = Cipher.getInstance("IDEA");
// initialize the cipher with the key
cipher.init(Cipher.ENCRYPT_MODE, sk);
// enctypt!
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
}
public static String decrypt(byte[] toDecrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance("IDEA");
kg.init(sr);
SecretKey sk = kg.generateKey();
// do the decryption with that key
Cipher cipher = Cipher.getInstance("IDEA");
cipher.init(Cipher.DECRYPT_MODE, sk);
byte[] decrypted = cipher.doFinal(toDecrypt);
return new String(decrypted);
}
}
But when i run the code i get this exception:
Exception in thread "main" java.security.NoSuchAlgorithmException: IDEA KeyGenerator not available
at javax.crypto.KeyGenerator.<init>(KeyGenerator.java:169)
at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:223)
at ideaalgoritam.IDEAalgoritam.encrypt(IDEAalgoritam.java:27)
at ideaalgoritam.IDEAalgoritam.main(IDEAalgoritam.java:16)
In jdk and jre security lib folder i've added security provider bouncy castle http://prntscr.com/j516zx. But i still get this exception.
Does anyone know how can i solve this problem so that i can run this code?
I am using this below (E.1) for my application, there is obviously a huge glaring security hole in this that I recognize and understand. I have grown interested in encryption and want to understand it better, I need to generate a random key along with an IV but am unsure how to do so properly Can someone explain to me whom is familiar with AES encryption how this works (IV & KEY) So I am better able to understand in the future and can apply my knowledge, essentially I just want to make the code more secure, thank you.
(E.1)
byte[] key = "mykey".getBytes("UTF-8");
private byte[] getKeyBytes(final byte[] key) throws Exception {
byte[] keyBytes = new byte[16];
System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length));
return keyBytes;
}
public Cipher getCipherEncrypt(final byte[] key) throws Exception {
byte[] keyBytes = getKeyBytes(key);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher;
}
public void encrypt(File in, File output, byte[] key) throws Exception {
Cipher cipher = getCipherEncrypt(key);
FileOutputStream fos = null;
CipherOutputStream cos = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(in);
fos = new FileOutputStream(output);
cos = new CipherOutputStream(fos, cipher);
byte[] data = new byte[1024];
int read = fis.read(data);
while (read != -1) {
cos.write(data, 0, read);
read = fis.read(data);
System.out.println(new String(data, "UTF-8").trim());
}
cos.flush();
} finally {
System.out.println("performed encrypt method now closing streams:\n" + output.toString());
cos.close();
fos.close();
fis.close();
}
}
public void watchMeEncrypt(){
encrypt(file, new File ("example.txt),key);
An AES key simply consists of random bytes. For CBC mode the IV mode should also be randomized (at least to an attacker). So in general you can simply use a SecureRandom instance to create the key and IV. The IV can then be included with the ciphertext; usually it is simply put in front of it.
With Java it is better to use a KeyGenerator though. If you look at the implementation of it in the SUN provider it will probably amount to the same thing. However using a KeyGenerator is more compatible with various kinds of keys and providers. It may well be that it is a requirement for generating keys in e.g. smart cards and HSM's.
So lets show a class with three simple methods:
package nl.owlstead.stackoverflow;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Optional;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class CreateKeyAndIVForAES_CBC {
public static SecretKey createKey(final String algorithm, final int keysize, final Optional<Provider> provider, final Optional<SecureRandom> rng) throws NoSuchAlgorithmException {
final KeyGenerator keyGenerator;
if (provider.isPresent()) {
keyGenerator = KeyGenerator.getInstance(algorithm, provider.get());
} else {
keyGenerator = KeyGenerator.getInstance(algorithm);
}
if (rng.isPresent()) {
keyGenerator.init(keysize, rng.get());
} else {
// not really needed for the Sun provider which handles null OK
keyGenerator.init(keysize);
}
return keyGenerator.generateKey();
}
public static IvParameterSpec createIV(final int ivSizeBytes, final Optional<SecureRandom> rng) {
final byte[] iv = new byte[ivSizeBytes];
final SecureRandom theRNG = rng.orElse(new SecureRandom());
theRNG.nextBytes(iv);
return new IvParameterSpec(iv);
}
public static IvParameterSpec readIV(final int ivSizeBytes, final InputStream is) throws IOException {
final byte[] iv = new byte[ivSizeBytes];
int offset = 0;
while (offset < ivSizeBytes) {
final int read = is.read(iv, offset, ivSizeBytes - offset);
if (read == -1) {
throw new IOException("Too few bytes for IV in input stream");
}
offset += read;
}
return new IvParameterSpec(iv);
}
public static void main(String[] args) throws Exception {
final SecureRandom rng = new SecureRandom();
// you somehow need to distribute this key
final SecretKey aesKey = createKey("AES", 128, Optional.empty(), Optional.of(rng));
final byte[] plaintext = "owlstead".getBytes(UTF_8);
final byte[] ciphertext;
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = createIV(aesCBC.getBlockSize(), Optional.of(rng));
aesCBC.init(Cipher.ENCRYPT_MODE, aesKey, ivForCBC);
baos.write(ivForCBC.getIV());
try (final CipherOutputStream cos = new CipherOutputStream(baos, aesCBC)) {
cos.write(plaintext);
}
ciphertext = baos.toByteArray();
}
final byte[] decrypted;
{
final ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext);
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = readIV(aesCBC.getBlockSize(), bais);
aesCBC.init(Cipher.DECRYPT_MODE, aesKey, ivForCBC);
final byte[] buf = new byte[1_024];
try (final CipherInputStream cis = new CipherInputStream(bais, aesCBC);
final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int read;
while ((read = cis.read(buf)) != -1) {
baos.write(buf, 0, read);
}
decrypted = baos.toByteArray();
}
}
System.out.println(new String(decrypted, UTF_8));
}
}
Note that you may not always want to generate and distribute an AES key "out-of-band". Here are a few other methods of generating a key (part #2 onwards). You may also want to take a look at more advanced exception handling for the cryptographic operation.
I wrote a little test case for an AES encryption and decryption. The plan is to read some text from a file, encrypt it with a key and decrypt it again. Now the problem is, that the text is always the same, a wrong password does not result in unreadable text.
Where is the problem in the code or did I make a fundamental mistake ?
Main.java
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws Exception {
new Main();
}
public Main() throws Exception {
Reader reader = new Reader();
String text = reader.readFile("/home/benjamin/Test.txt");
System.out.println("Original text before encryption: " + text);
// User A verschlüsselt und speichert ab
Crypto crypto = new Crypto();
SecretKeySpec secretkey = crypto.generateSecretKey("123456aA");
byte[] encryptedtext = crypto.encrypt(text, secretkey);
// User B lädt Datei und kennt das Passwort
Crypto crypto2 = new Crypto();
SecretKeySpec secretkey2 = crypto2.generateSecretKey("1kkk23456aAjbhhjbhjb");
byte[] decryptedtext = crypto2.decrypt(encryptedtext, secretkey2);
System.out.println("Original text after encryption: " + new String(decryptedtext, "UTF-8"));
}
}
Crypto.java
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
public SecretKeySpec generateSecretKey(String password) throws Exception {
MessageDigest shahash = MessageDigest.getInstance("SHA-1");
byte[] key = shahash.digest();
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
public byte[] encrypt(String text, SecretKeySpec secretkey) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretkey);
return cipher.doFinal(text.getBytes());
}
public byte[] decrypt(byte[] encryptedtext, SecretKeySpec secretkey) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretkey);
return cipher.doFinal(encryptedtext);
}
}
This is the problem:
public SecretKeySpec generateSecretKey(String password) throws Exception {
MessageDigest shahash = MessageDigest.getInstance("SHA-1");
byte[] key = shahash.digest();
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
You don't use password anywhere within generateSecretKey, so it'll create the same secret key every time...
If you change it to:
public SecretKeySpec generateSecretKey(String password) throws Exception {
MessageDigest shahash = MessageDigest.getInstance("SHA-1");
byte[] key = shahash.digest(password.getBytes("UTF-8"));
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
then it will fail as expected when given the wrong password. That doesn't necessarily mean it's the best way of creating a secret key, or that any of the rest of the crypto code is appropriate, but I don't have enough experience to comment on that.
The generateSecretKey method is broken. It generates the key based on the digest of the empty string – the password argument is ignored.
There are also other issues. ECB mode is not secure. Key derivation is very weak here. Depending on the platform default character encoding is not a good idea.