I am running a java string encryption/decryption class that i got from the internet! Here is the class with little modification :
public class EncrypterDecrypter
{
Cipher ecipher;
Cipher dcipher;
EncrypterDecrypter(SecretKey key)
{
try {
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (javax.crypto.NoSuchPaddingException e) {
} catch (java.security.NoSuchAlgorithmException e) {
} catch (java.security.InvalidKeyException e) {
}
}
}
public class EncryptionTester
{
public static void main(String[] args)
{
try
{
//Generate a temporary key.
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
//Create Encrypter/Decrypter class
EncrypterDecrypter crypto = new EncrypterDecrypter(key);
//More lines of code to use crypto object
}
catch (Exception e)
{
}
}
}
My problem is that each time i create an new instance of EncrypterDecrypter class i get differents encrypted string yet the string to encrypt is still the same! My mind tells me that the problem would be the SecretKey object which keeps changing each time there is a new instance created, i would like to know how i can make the SecretKey object the same for all instances of Encrypter/Decrypter Class if that be the cause of the problem!
If you used the javax.crypto package, then the encrypt and decryp methods look okay.
Try to generate your key like that:
final SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
final SecretKey key = skf.generateSecret(new DESKeySpec(new byte [] {/*The key*/}));
instance.EncrypterDecrypter(key); //Initialization of your Cipher objects
String encrypted = instance.encrypt("This is a test");
System.out.println(instance.decrypt(encrypted)); //"This is a test"
You should do something in the catches.
Generate SecretKey from a byte array..
byte raw[] = new byte[]{0x001,0x002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002,0X002};
SecretKeySpec spec = new SecretKeySpec(raw, "DES");
Related
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
class CryptAES {
static final String cipher_type = "AES/CBC/PKCS5Padding";
public static void main(String[] args) {
String key = args[0];
String iv = args[1];
String data = args[2];
byte[] enc = encode(key, iv, data.getBytes());
byte[] dec = decode(key, iv, enc);
for (int i = 0; i < enc.length; i++) {
System.out.printf("%02x", enc[i]);
}
System.out.println();
System.out.println(new String(dec));
}
public static byte[] encode(String skey, String iv, byte[] data) {
return process(Cipher.ENCRYPT_MODE, skey, iv, data);
}
public static byte[] decode(String skey, String iv, byte[] data) {
return process(Cipher.DECRYPT_MODE, skey, iv, data);
}
private static byte[] process(int mode, String skey, String iv, byte[] data) {
SecretKeySpec key = new SecretKeySpec(skey.getBytes(), "AES");
AlgorithmParameterSpec param = new IvParameterSpec(iv.getBytes());
try {
Cipher cipher = Cipher.getInstance(cipher_type);
cipher.init(mode, key, param);
return cipher.doFinal(data);
} catch (Exception e) {
System.err.println(e.getMessage());
throw new RuntimeException(e);
}
}
}
exception in thread main java.lang.arrayindexoutofboundsexception index out of bounds for length 0
exception in thread main java.lang.arrayindexoutofboundsexception index out of bounds for length 0
As #rzwitserloot pointed out, you need to check if there have been arguments passed into the application in the command line.
You should always be checking for null/empty/invalid values when a user can give input. A simple example on how to prevent the original error and throw a more meaningful error is below:
public static void main(String[] args) {
if (null == args || args.length != 3) {
throw new IOException("Please add arguments key, iv and data");
}
String key = args[0];
String iv = args[1];
String data = args[2];
...
}
You may want to be able to not have any inputs, or only input 1/2 out of the 3 arguments. For that you need to check if the argument value exists and then access it.
I am trying to encrypt a json string using the below code:
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static Cipher getDefaultCipherInstance(int mode)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException {
byte[] key = Base64.getDecoder().decode("encryptionKey".getBytes(CHARSET));
IvParameterSpec iv = new IvParameterSpec("RandomVector".getBytes(CHARSET));
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(mode, skeySpec, iv);
return cipher;
}
public static String encryptText(String plainText) {
try {
Cipher cipher = getDefaultCipherInstance(Cipher.ENCRYPT_MODE);
byte[] cipherText = cipher.doFinal(plainText.getBytes(CHARSET));
return new String(Base64.getEncoder().encode(cipherText));
} catch (Exception ex) {
LOG.error("Problem encryptingText",ex);
return null;
}
}
public static String decryptText(String cipherText) {
try {
Cipher cipher = getDefaultCipherInstance(Cipher.DECRYPT_MODE);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(decrypted);
} catch (Exception ex) {
LOG.debug("Problem during decrypt text: " + cipherText, ex);
return null;
}
}
It works fine most of the times but sometimes I see weird characters in the decrypted string like "\u001A=`�["Q�\u001D)��ۉ�d":\ , this is corrupting the json and we are not able to deserialize json to object.
Any idea what could be the problem here?
Update::
I added the following code to test encryption/decryption in a concurrent(multi-threaded) environment:
public class EncryptionTest {
#Test
public void test() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(25);
String text = "Hi there Ithanks for cimngng";
for(int i = 0; i < 5; i++) {
System.out.println("Iteration: " + i);
executorService.submit(new EncryptionRunnable(text));
}
Thread.currentThread().join();
}
static class EncryptionRunnable implements Runnable {
private String text;
public EncryptionRunnable(String text) {
this.text = text;
}
#Override
public void run() {
int i = 0;
while(i < 10) {
String encrypted = encryptText(text);
String prefix = Thread.currentThread().getName() + "::" + i + ":: ";
System.out.println(prefix + "encrypted:: " + encrypted);
try {
System.out.println(prefix + "decrypted:: " + decryptText(encrypted));
} catch (Exception e) {
System.out.println(prefix + "decrypted:: ");
e.printStackTrace();
}
i++;
}
}
}
}
I see that all of the outputs were correct but for one of the output, it produced strange characters like this:
pool-1-thread-5::0:: decrypted:: ȼ����S}�q��j� for cimngng
Even the encrypted string is same for every encryption. Can anybody help now? Note: I am using the same cipher instance for encryption and same for decryption.
Here is a snapshot of the output of the above code.
I want to encode my password using an encryption key. but I got a null value, when printing the encoded password. I have attached my code below:
public class FirstJava {
private static final Long ENCRYPTION_KEY = 29190210908917L;
public static String encrypt(String strToEncrypt, byte[] key) {
if (strToEncrypt == null)
return strToEncrypt;
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes()));
} catch (Exception exception) {
System.out.println("ERROR");
}
return null;
}
public static void main(String[] args) {
String password = "12345678";
byte[] arr = String.valueOf(ENCRYPTION_KEY).getBytes();
String passwordEnc = encrypt(password,arr);
System.out.println("passwordEnc============= "+passwordEnc);
}
}
AES only supports key sizes of 16, 24 or 32 bytes. Your key length is 14, add 2 more digits to your key and it will work.
private static final Long ENCRYPTION_KEY = 2919021090891712L; //16 bytes
I am facing an issue with the following code
public static void main(String[] args) throws NoSuchAlgorithmException {
String key = "test";
SecretKeySpec secretKeySpec = new
SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
Mac mac = Mac.getInstance("HmacSHA512");
try {
if (null != mac) {
mac.init(secretKeySpec);
}
} catch (InvalidKeyException e) {
}
IntStream.range(1, 12).parallel().forEach(d->{
final byte[] bytes = "somestring".getBytes(StandardCharsets.UTF_8);
final byte[] doFinal= mac.doFinal(bytes);
String digest = Base64.getEncoder().encodeToString(doFinal);
LOGGER.info("digest -- {} ", digest);
});
}
Even the string is the same but digests generated using a mac.doFinal is different. This is just a showcase of the issue. I have used the same code in my spring reactive application where mac is a bean and digest generated every time when user make a request which is a concurrent request where also i have seen these weird behavior.
I can get a public key from a certificate file,and use code below to encrypt a message with sm2engine.
public static String encrypt(String data, PublicKey publicKey)
{
ECPublicKeyParameters localECPublicKeyParameters = null;
if (publicKey instanceof BCECPublicKey)
{
BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(
localECParameterSpec.getCurve(), localECParameterSpec.getG(),
localECParameterSpec.getN());
localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(),
localECDomainParameters);
}
SM2Engine localSM2Engine = new SM2Engine();
localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters,
new SecureRandom()));
byte[] arrayOfByte2;
try
{
arrayOfByte2 = localSM2Engine.processBlock(data.getBytes(), 0, data.getBytes().length);
return new String(Base64.encode(arrayOfByte2));
}
catch (InvalidCipherTextException e)
{
e.printStackTrace();
return null;
}
But it is not enveloped,I do not know how to add an envelop on it,but I know how to add envelop without sm2egine:
public static String encryptMessage(String message, X509Certificate cert) throws Exception {
CMSEnvelopedDataGenerator gen = new CMSEnvelopedDataGenerator();
gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert));
OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BouncyCastleProvider.PROVIDER_NAME).build();
CMSTypedData content = new CMSProcessableByteArray(message.getBytes("UTF-8"));
CMSEnvelopedData data = gen.generate(content, encryptor);
String encryptedMessage = new String(Base64.encode(data.getEncoded()));
return encryptedMessage;
}
but now I must use the special algorithm called sm4 as the symmetric algorithm to encrypt the content first,not aes.And then use sm2 to encypt the key of sm4,all as it defined in pkcs7.so how to join these two code fragment?
All special algorithms seem can be implemented by BouncyCastle method,but there is no sm4 in CMSAlgorithm class,but I found a GMObjectIndenrifier.sms4_cbc,and pass it as a parameter,but got a exception:
no such algorithm.
More info:after I parse the certificate from a file, and call certificate.getSigAlgName(),its name is SM3WITHSM2