Converting TripleDes algorithm - java

I want to convert following C# to java code, so we can decrypt old messages and encrypt new ones in java.
public class encryptionUtil
{
private TripleDESCryptoServiceProvider TripleDes;
private UTF8Encoding utfEncoding;
private byte[] key;
private byte[] iv;
private string sysKey;
private string sysUser;
public encryptionUtil()
{
this.TripleDes = new TripleDESCryptoServiceProvider();
this.utfEncoding = new UTF8Encoding();
this.key = this.utfEncoding.GetBytes("123456789012345678901234");
this.iv = this.utfEncoding.GetBytes("12345678");
this.sysKey = WindowsIdentity.GetCurrent().Name;
this.sysUser = WindowsIdentity.GetCurrent().User.Value;
}
public string EncryptData(string plaintext)
{
string str;
try
{
plaintext = plaintext + this.sysUser;
byte[] bytes = Encoding.Unicode.GetBytes(plaintext);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, this.TripleDes.CreateEncryptor(this.key, this.iv), CryptoStreamMode.Write);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
str = Convert.ToBase64String(memoryStream.ToArray());
}
catch (Exception ex)
{
ProjectData.SetProjectError(ex);
str = plaintext ;
ProjectData.ClearProjectError();
}
return str;
}
public string DecryptData(string encryptedtext)
{
string str;
try
{
byte[] buffer = Convert.FromBase64String(encryptedtext);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, this.TripleDes.CreateDecryptor(this.key, this.iv), CryptoStreamMode.Write);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.FlushFinalBlock();
string[] strArray = Encoding.Unicode.GetString(memoryStream.ToArray());
str = Microsoft.VisualBasic.CompilerServices.Operators.CompareString(strArray[1], this.token, false) != 0 ? "" : strArray[0];
}
catch (Exception ex)
{
ProjectData.SetProjectError(ex);
str = "";
ProjectData.ClearProjectError();
}
return str;
}
Encryption output in c# for "Encrypt this in java"
7UlYtjB6Nls4Q3Ac4VzdY2k6hVRa1Eqjyt2ZG4818WxLCwFhx1fEeTCvOStTylyMM5ucL4DmF1NKBRga44Yqrj89VHRKZuWnFC24jMkSxucZkB3niLa7WOT4GKlii7716w6TC9iJGYLhy8mY1kqwaw==
Java code written so far, how to proceed further so that I get same result as above?
package com.mycompany.util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class EncryptionUtil {
private static SecretKey sharedkey;
private static byte [] sharedvector;
static {
int keySize = 168;
int ivSize = 8;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(keySize);
sharedkey = keyGenerator.generateKey();
sharedvector = new byte [ivSize];
byte [] data = sharedkey.getEncoded();
int half = ivSize / 2;
System.arraycopy(data, data.length-half, sharedvector, 0, half);
System.arraycopy(sharedvector, 0, sharedvector, half, half);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static void main(String [] args) throws Exception {
String plainText = "Encrypt this in java";
String systemId= "949367136-5890454";
String dataText = plainText+systemId
String keyString = "key1234";
String ivString = "iv1234";
try {
byte[] keyBytes = keyString.getBytes("UTF-8");
byte[] ivBytes = ivString.getBytes("UTF-8");
byte[] dataBytes = plainText.getBytes("UTF-8");
System.out.println("key="+keyBytes.toString());
System.out.println("iv="+ivBytes.toString());
System.out.println("plaintextBytesUTF-8="+dataBytes.toString());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String Encrypt(String val) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));
return new sun.misc.BASE64Encoder().encode(cipher.doFinal(val.getBytes()));
}
public static String Decrypt(String val) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));
return new String(cipher.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(val)));
}
}

Related

Angular Encryption with AES has different result with old Java Code

So usually i use one java file to encrypt and decrypt a string to hex with AES,
then my angular app want to consume api, that use the result of it.
this is my old java code
package decryptoor;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.Formatter;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoAndroidKoplak {
private static final String TEXT_ENCODING = "UTF-8";
private static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String ENCRYPTION_ALGORITM = "AES";
private static final String TAG = "Crypto";
private Cipher cipher;
private IvParameterSpec initialVector;
// private static void DEBUG(String msg){
// if(IDefines.DEBUG_LOG_TRACE){
// Log.i(TAG, msg);
// }
// }
public CryptoAndroidKoplak() {
try {
cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
initialVector = new IvParameterSpec(new byte[16]);
} catch (Exception e) {
System.out.println(e.toString());
}
}
public String encryptString(String plainText, String key) throws Exception {
return toHexString(encrypt(plainText, key)).toUpperCase();
}
public byte[] encrypt(String plainText, String key) throws Exception {
byte[] byteKey = getKeyBytes(key);
byte[] plainData = plainText.getBytes(TEXT_ENCODING);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, ENCRYPTION_ALGORITM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, initialVector);
return cipher.doFinal(plainData);
}
public String decryptString(String encryptedText, String key) throws Exception {
return new String(decrypt(encryptedText, key));
}
public byte[] decrypt(String encryptedText, String key) throws Exception {
byte[] byteKey = getKeyBytes(key);
byte[] encryptData = hexToAscii(encryptedText);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, ENCRYPTION_ALGORITM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, initialVector);
return cipher.doFinal(encryptData);
}
public static String toMD5(String text) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] data = text.getBytes(TEXT_ENCODING);
return toHexString(md.digest(data));
}
public static String toSHA1(String text) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] data = text.getBytes(TEXT_ENCODING);
return toHexString(md.digest(data));
}
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
Formatter formatter = new Formatter(sb);
for (byte b : bytes) {
formatter.format("%02x", b);
}
return sb.toString();
}
private static byte[] hexToAscii(String hexStr) {
byte[] buff = new byte[hexStr.length() / 2];
int offset = 0;
for (int i = 0; i < hexStr.length(); i += 2) {
String str = hexStr.substring(i, i + 2);
buff[offset++] = (byte) Integer.parseInt(str, 16);
}
return buff;
}
private static byte[] getKeyBytes(String key) throws UnsupportedEncodingException {
byte[] keyBytes = new byte[16];
byte[] parameterKeyBytes = key.getBytes("UTF-8");
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
}
and this is my code in angular
import { Injectable } from '#angular/core';
import * as CryptoJS from 'crypto-js';
#Injectable({
providedIn: 'root'
})
export class Encryption {
constructor() {}
encryptAesToString(stringToEncrypt: string, key: string): string {
// first way
// let encrypted;
// try {
// encrypted = CryptoJS.AES.encrypt(JSON.stringify(stringToEncrypt), key);
// } catch (e) {
// console.log(e);
// }
// encrypted = CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
// return encrypted;
// second way
// var b64 = CryptoJS.AES.encrypt(stringToEncrypt, key).toString();
// var e64 = CryptoJS.enc.Base64.parse(b64);
// var eHex = e64.toString(CryptoJS.enc.Hex);
// return eHex;
// third way
const key2 = CryptoJS.enc.Utf8.parse(key);
const iv = CryptoJS.enc.Utf8.parse(key);
const encrypted = CryptoJS.AES.encrypt(stringToEncrypt, key2, {
keySize: 16,
iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
let eHex = CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
return encrypted;
}
decryptAesformString(stringToDecrypt: string, key: string): string {
let decrypted: string = '';
try {
const bytes = CryptoJS.AES.decrypt(stringToDecrypt, key);
if (bytes.toString()) {
decrypted = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
}
} catch (e) {
console.log(e);
}
return decrypted;
}
}
i have try three code, the first one doesn't return hex, so i try 2 more ways but it doesn't show same encrypted string with the old java code so i cant consume the api.
any idea why this happen?
if you have better way to encrypt and decrypt with key that more simple both in angular and java, it will really help.
many thanks
after give up on how to make it same with my old java code, finally i try to make a new one hehe...
so after i read this answer, then i understand CryptoJS (library that i use in angular) implements the same key derivation function as OpenSSL. so i choose to use basic CryptoJS function to encrypt my string like this
var text = "The quick brown fox jumps over the lazy dog. 👻 👻";
var secret = "René Über";
var encrypted = CryptoJS.AES.encrypt(text, secret);
encrypted = encrypted.toString();
console.log("Cipher text: " + encrypted);
after that, what i need to do is make new java file to encrypt and decrypt aes OpenSsl, and i get what i need here in this answer. i use robert answer, cause accepted answer not really give me what i need.
but like the first answer mentioned, to encrypt and decrypt in this way, we have to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy. Otherwise, AES with key size of 256 won't work and throw an exception:(you won't need JCE with up-to-date java version)
so i add some functionality to force using AES with key size of 256 without to install JCE here. note to use this, actually isnt recomended, please read the comment in ericson answer
then this is my final code to encrypt and decrypt like OpenSsl
package decryptoor;
import groovy.transform.CompileStatic;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import static java.nio.charset.StandardCharsets.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
/**
* Mimics the OpenSSL AES Cipher options for encrypting and decrypting messages using a shared key (aka password) with symetric ciphers.
*/
#CompileStatic
class OpenSslAes {
/** OpenSSL's magic initial bytes. */
private static final String SALTED_STR = "Salted__";
private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);
static String encryptAndURLEncode(String password, String clearText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, InvalidAlgorithmParameterException, BadPaddingException, UnsupportedEncodingException {
String encrypted = encrypt(password, clearText);
return URLEncoder.encode(encrypted, UTF_8.name() );
}
/**
*
* #param password The password / key to encrypt with.
* #param data The data to encrypt
* #return A base64 encoded string containing the encrypted data.
*/
static String encrypt(String password, String clearText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, InvalidAlgorithmParameterException, BadPaddingException {
removeCryptographyRestrictions();
final byte[] pass = password.getBytes(US_ASCII);
final byte[] salt = (new SecureRandom()).generateSeed(8);
final byte[] inBytes = clearText.getBytes(UTF_8);
final byte[] passAndSalt = array_concat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] data = cipher.doFinal(inBytes);
data = array_concat(array_concat(SALTED_MAGIC, salt), data);
return Base64.getEncoder().encodeToString( data );
}
/**
* #see http://stackoverflow.com/questions/32508961/java-equivalent-of-an-openssl-aes-cbc-encryption for what looks like a useful answer. The not-yet-commons-ssl also has an implementation
* #param password
* #param source The encrypted data
* #return
*/
static String decrypt(String password, String source) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
removeCryptographyRestrictions();
final byte[] pass = password.getBytes(US_ASCII);
final byte[] inBytes = Base64.getDecoder().decode(source);
final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, SALTED_MAGIC.length);
if (!Arrays.equals(shouldBeMagic, SALTED_MAGIC)) {
throw new IllegalArgumentException("Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.");
}
final byte[] salt = Arrays.copyOfRange(inBytes, SALTED_MAGIC.length, SALTED_MAGIC.length + 8);
final byte[] passAndSalt = array_concat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
return new String(clear, UTF_8);
}
private static byte[] array_concat(final byte[] a, final byte[] b) {
final byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
private static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
return;
}
try {
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false; JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
setFinalStatic(isRestrictedField, true);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
}
catch (final Exception e) {
e.printStackTrace();
}
}
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
private static boolean isRestrictedCryptography() {
// This simply matches the Oracle JRE, but not OpenJDK.
return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}
}

encoding and decoding international characters

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import com.Ostermiller.util.Base64;
import com.Ostermiller.util.MD5;
import java.net.URLEncoder;
public class EnDecryptor {
public static void addProvider()
{
if (Security.getProvider("IBMJCE") == null) {
// IBMJCE is not installed, install it.
try
{
Security.addProvider
((Provider)Class.forName("com.ibm.crypto.provider.IBMJCE").newInstance());
}
catch (Exception ex) {
AuthLogger.logFatal("EnDecryptor:addProvider():Cannot install provider: " + ex.getMessage());
}
}
}
public static String encrypt(String word)
{
addProvider();
String encWord="";
byte[] encryptedWordbytes=null;
try
{
if (null == word)
{
throw new NullPointerException("EnDecryptor:encrypt(): No string to be encrypted provided!");
}
AuthLogger.logDebug("EnDecryptor:encrypt():Generating an encryption key...");
encryptedWordbytes = MD5.getHash(word);
AuthLogger.logDebug("EnDecryptor:encrypt():MD5 HASH length:"+encryptedWordbytes.length);
AuthLogger.logDebug("EnDecryptor:encrypt():MD5 HASH :"+new String(encryptedWordbytes));
// Create a Rijndael key
SecretKeySpec KeySpec = new SecretKeySpec(encryptedWordbytes, "AES");
AuthLogger.logDebug("EnDecryptor:encrypt():Done generating the key...");
Cipher cipherKey =Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");
byte[] iv = new byte[16];
IvParameterSpec spec = null;
for(int i=0;i<16;i++)
{
iv[i]=(byte)i;
}
spec = new IvParameterSpec(iv);
cipherKey.init(Cipher.ENCRYPT_MODE, KeySpec, spec);
byte[] encryptedDataBytes = cipherKey.doFinal(word.getBytes());
String base64data = new String(Base64.encode(encryptedDataBytes));
AuthLogger.logDebug("EnDecryptor:encrypt():BASE64DATA="+base64data);
byte[] encryptedKeyBytes = MD5.getHash(encryptedDataBytes);
SecretKeySpec KeySpec2 = new SecretKeySpec(encryptedKeyBytes, "AES");
Cipher cipherKey2 = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
cipherKey2.init(Cipher.ENCRYPT_MODE, KeySpec2, spec);
byte[] encryptedkey = cipherKey2.doFinal(encryptedWordbytes);
String base64Key = new String(Base64.encode(encryptedkey));
AuthLogger.logDebug("EnDecryptor:encrypt():BASE64Key="+base64Key);
String parm1 = "Data=" + URLEncoder.encode(base64data, "UTF-8") ;//$$$ encode(base64data);
String parm2 = "A=" + URLEncoder.encode(base64Key, "UTF-8") ;//$$$ encode(base64Key);
//encWord="Data="+parm1+"&A="+parm2;
encWord=parm1+"&"+parm2;
}catch(Exception e)
{
e.printStackTrace();
}
return encWord;
}
public static String decrypt(String encData, String encKey)
{
addProvider();
String decryptedData="";
byte[] abKeysKey=null;
try
{
byte[] abEncryptedKeys=(Base64.decode(encKey.getBytes()));
if (null == encData)
{
throw new NullPointerException("EnDecryptor:decrypt(): No data to be decryopted provided!");
}
AuthLogger.logDebug("EnDecryptor:decrypt():Generating a the HASH of the data...");
abKeysKey = MD5.getHash(Base64.decode(encData.getBytes()));
// Create a Rijndael key
SecretKeySpec KeySpec = new SecretKeySpec(abKeysKey, "AES");
Cipher cipherKey = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
IvParameterSpec spec = null;
byte[] iv = new byte[16];
for(int i=0;i<16;i++)
{
iv[i]=(byte)i;
}
spec = new IvParameterSpec(iv);
cipherKey.init(Cipher.DECRYPT_MODE, KeySpec, spec);
byte[] abKeys = cipherKey.doFinal(abEncryptedKeys);
String base64key = new String(Base64.encode(abKeys));
AuthLogger.logDebug("EnDecryptor:decrypt():BASE64 DECODED KEY="+base64key);
//byte[] encryptedKeyBytes = MD5.getHash(encryptedDataBytes);
SecretKeySpec KeySpec2 = new SecretKeySpec(abKeys, "AES");
Cipher cipherKey2 = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
cipherKey2.init(Cipher.DECRYPT_MODE, KeySpec2, spec);
byte[] decodedData = cipherKey2.doFinal(Base64.decode(encData.getBytes()));
decryptedData= new String(decodedData);
AuthLogger.logDebug("EnDecryptor:decrypt():decoded data="+decryptedData);
}catch(Exception e)
{
e.printStackTrace();
}
return decryptedData;
}
}
in this code i can mostly encode A-Z and a-z, 0-9 and +,/ but i cannot encode any special characters like(~,#,!, etc) or international characters like(ê,etc)
can anyone suggest anything because i need to encode and decode characters like these any help will be appreciated.
New edit
if i use import java.io.IOException; will it solve my issue?
i know it's not good to use sun packages but i have done this it encodes mostly all the spacial and international characters except one or two here is the code
import java.io.IOException;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
// Java Base64 Encoder / Java Base64 Decoder
public class Base64Test {
public static void main(String[] args) {
BASE64Decoder decoder = new BASE64Decoder();
BASE64Encoder encoder = new BASE64Encoder();
try {
String encodedBytes = encoder.encodeBuffer("(####&&&&&)".getBytes());
System.out.println("encodedBytes " + encodedBytes);
byte[] decodedBytes = decoder.decodeBuffer(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));
} catch (IOException e) {
e.printStackTrace();
}
}
}
OUTPUT
encodedBytes KEBAQEAmJiYmJik=
decodedBytes (####&&&&&)

Java encryption performance to hide primary keys

I need to hide certain raw values from end user output (mostly primary keys, could be ~100 of them per request) simply so that the database can't easily be probed or iterated through. Speed of the encryption is of higher importance than the actual impenetrability of the values.
I am currently using PBEWithMD5AndDES in the following wrapper - is this overkill? I am new to using Java as a web backend.
public class SecurityHelper {
private static final String DEFAULT_KEY = "some-key-here";
private SecretKey secretKey;
private PBEParameterSpec parameterSpec;
private Cipher cipher;
public SecurityHelper() {
try {
char[] moduleKeyChars = DEFAULT_KEY.toCharArray();
KeySpec keySpec = new PBEKeySpec(moduleKeyChars);
secretKey = SecretKeyFactory.getInstance(
"PBEWithMD5AndDES").generateSecret(keySpec);
parameterSpec = new PBEParameterSpec(new byte[8], 1);
cipher = Cipher.getInstance("PBEWithMD5AndDES");
} catch (Exception e) {
e.printStackTrace();
}
}
public String encrypt(String secret) {
String encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] stateBytes = cipher.doFinal(secret.getBytes("UTF-8"));
encrypted = DatatypeConverter.printBase64Binary(stateBytes);
} catch (Exception e) {
e.printStackTrace();
}
return encrypted;
}
public String decrypt(String encrypted) {
String decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
byte[] stringBinary = DatatypeConverter.parseBase64Binary(encrypted);
decrypted = new String(cipher.doFinal(stringBinary));
} catch (Exception e) {
e.printStackTrace();
}
return decrypted;
}
}
Or am I dramatically better off using something like XOR cipher?
If you do want to hide the values from a user, I don't see why you should be either encrypting or hashing them. What you should be doing is to generate random and unique keys. Have you thought of using GUIDs instead ?
If you think GUIDs are too long, you could generate a random string of a predefined length. Make your database column a unique index for the benefit of faster searching.
This is how URL shortners such as bit.ly or goo.gl works. This would prevent anyone from crawling through your database using primary keys.
Yes, encryption is probably overkill. You should however not fall into a trap and use less secure cryptographic primitives because of it. Especially using CBC mode security, a static salt etc. are really mistakes you should avoid. XOR or DES encryption is really not worth the name, these encryption schemes can be broken in minutes.
If encryption is overkill with regards to server performance is a question only you can answer. Usually IO and complex SQL queries will task your system more than simple symmetric encryption of a few bytes of data.
I'll show you your class retrofitted with GCM and - in case that's not available or if the tag size of 12 bytes is too much overhead - CTR mode encryption.
You should probably only do this if it is not possible to use (random) GUID's instead.
WARNING: I would not consider the following classes to have enough input parameter checking (integer overflows etc.). I get bored when trying to implement all those checks and JUnit tests (without getting payed for it anyway :P ). Sanitize your input before calling any of the functions.
AES/GCM:
import static java.nio.charset.StandardCharsets.*;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class SecurityHelperGCM {
private static final int NONCE_SIZE = 8;
private static final int TAG_SIZE = 12;
// make sure that the hexadecimals represent a *truly random* byte array
// (e.g. use SecureRandom)
private final SecretKey STATIC_SECRET_KEY = new SecretKeySpec(
hexDecode("66e517bb5fd7df840060aed7e8b58986"), "AES");
private Cipher cipher;
private static byte[] hexDecode(final String hex) {
final byte[] data = new byte[hex.length() / 2];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2),
16);
}
return data;
}
public SecurityHelperGCM() {
try {
this.cipher = Cipher.getInstance("AES/GCM/NoPadding");
} catch (final Exception e) {
e.printStackTrace();
}
}
private static int generateRandomNonce(final byte[] nonceBuffer,
final int offset, final int size) {
final SecureRandom rng = new SecureRandom();
final byte[] nonce = new byte[size];
rng.nextBytes(nonce);
System.arraycopy(nonce, 0, nonceBuffer, offset, size);
clearArray(nonce);
return offset + size;
}
private static void clearArray(final byte[] nonce) {
// clean up...
for (int i = 0; i < nonce.length; i++) {
nonce[i] = 0;
}
}
private static GCMParameterSpec generateGCMParametersFromNonce(
final byte[] nonceBuffer, final int offset, final int size,
final int blockSize) {
final GCMParameterSpec gcmParameters = new GCMParameterSpec(TAG_SIZE
* Byte.SIZE, nonceBuffer, offset, size);
return gcmParameters;
}
public String encrypt(final String secret) {
final byte[] plaintext = secret.getBytes(UTF_8);
final byte[] nonceAndCiphertext = new byte[NONCE_SIZE
+ plaintext.length + TAG_SIZE];
int offset = generateRandomNonce(nonceAndCiphertext, 0, NONCE_SIZE);
final GCMParameterSpec nonceIV = generateGCMParametersFromNonce(
nonceAndCiphertext, 0, NONCE_SIZE, this.cipher.getBlockSize());
try {
this.cipher.init(Cipher.ENCRYPT_MODE, this.STATIC_SECRET_KEY,
nonceIV);
offset += this.cipher.doFinal(plaintext, 0, plaintext.length,
nonceAndCiphertext, offset);
if (offset != nonceAndCiphertext.length) {
throw new IllegalStateException(
"Something wrong during encryption");
}
// Java 8 contains java.util.Base64
return DatatypeConverter.printBase64Binary(nonceAndCiphertext);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Missing basic functionality from Java runtime", e);
}
}
public String decrypt(final String encrypted) throws BadPaddingException {
final byte[] nonceAndCiphertext = DatatypeConverter
.parseBase64Binary(encrypted);
final GCMParameterSpec nonceIV = generateGCMParametersFromNonce(
nonceAndCiphertext, 0, NONCE_SIZE, this.cipher.getBlockSize());
try {
this.cipher.init(Cipher.DECRYPT_MODE, this.STATIC_SECRET_KEY,
nonceIV);
final byte[] plaintext = this.cipher.doFinal(nonceAndCiphertext,
NONCE_SIZE, nonceAndCiphertext.length - NONCE_SIZE);
return new String(plaintext, UTF_8);
} catch (final BadPaddingException e) {
throw e;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Missing basic functionality from Java runtime", e);
}
}
public static void main(final String[] args) {
final String secret = "owlstead";
final SecurityHelperGCM securityHelperGCM = new SecurityHelperGCM();
final String ct = securityHelperGCM.encrypt(secret);
String pt = null;
try {
pt = securityHelperGCM.decrypt(ct);
} catch (BadPaddingException e) {
System.out.println("Ciphertext tampered, take action!");
}
System.out.println(pt);
}
}
AES/CTR:
import static java.nio.charset.StandardCharsets.*;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class SecurityHelperCTR {
private static final int NONCE_SIZE = 8;
// make sure that the hexadecimals represent a *truly random* byte array
// (e.g. use SecureRandom)
private final SecretKey STATIC_SECRET_KEY = new SecretKeySpec(
hexDecode("66e517bb5fd7df840060aed7e8b58986"), "AES");
private Cipher cipher;
private static byte[] hexDecode(final String hex) {
final byte[] data = new byte[hex.length() / 2];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2),
16);
}
return data;
}
public SecurityHelperCTR() {
try {
this.cipher = Cipher.getInstance("AES/CTR/NoPadding");
} catch (final Exception e) {
e.printStackTrace();
}
}
private static int generateRandomNonce(final byte[] nonceBuffer,
final int offset, final int size) {
final SecureRandom rng = new SecureRandom();
final byte[] nonce = new byte[size];
rng.nextBytes(nonce);
System.arraycopy(nonce, 0, nonceBuffer, offset, size);
return offset + size;
}
private static IvParameterSpec generateIVFromNonce(
final byte[] nonceBuffer, final int offset, final int size,
final int blockSize) {
final byte[] ivData = new byte[blockSize];
System.arraycopy(nonceBuffer, offset, ivData, 0, size);
final IvParameterSpec iv = new IvParameterSpec(ivData);
return iv;
}
public String encrypt(final String secret) {
final byte[] plaintext = secret.getBytes(UTF_8);
final byte[] nonceAndCiphertext = new byte[NONCE_SIZE
+ plaintext.length];
int offset = generateRandomNonce(nonceAndCiphertext, 0, NONCE_SIZE);
final IvParameterSpec nonceIV = generateIVFromNonce(nonceAndCiphertext,
0, NONCE_SIZE, this.cipher.getBlockSize());
try {
this.cipher.init(Cipher.ENCRYPT_MODE, this.STATIC_SECRET_KEY,
nonceIV);
offset += this.cipher.doFinal(plaintext, 0, plaintext.length,
nonceAndCiphertext, offset);
if (offset != nonceAndCiphertext.length) {
throw new IllegalStateException(
"Something wrong during encryption");
}
// Java 8 contains java.util.Base64
return DatatypeConverter.printBase64Binary(nonceAndCiphertext);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Missing basic functionality from Java runtime", e);
}
}
public String decrypt(final String encrypted) {
final byte[] nonceAndCiphertext = DatatypeConverter
.parseBase64Binary(encrypted);
final IvParameterSpec nonceIV = generateIVFromNonce(nonceAndCiphertext,
0, NONCE_SIZE, this.cipher.getBlockSize());
try {
this.cipher.init(Cipher.DECRYPT_MODE, this.STATIC_SECRET_KEY,
nonceIV);
final byte[] plaintext = this.cipher.doFinal(nonceAndCiphertext,
NONCE_SIZE, nonceAndCiphertext.length - NONCE_SIZE);
// note: this may return an invalid result if the value is tampered
// with
// it may even contain more or less characters
return new String(plaintext, UTF_8);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Missing basic functionality from Java runtime", e);
}
}
public static void main(final String[] args) {
final String secret = "owlstead";
final SecurityHelperCTR securityHelper = new SecurityHelperCTR();
final String ct = securityHelper.encrypt(secret);
final String pt = securityHelper.decrypt(ct);
System.out.println(pt);
}
}

3DES Encryption Oracle/JAVA equivalent

I'm trying to migrate the oracle method dbms_obfuscation_toolkit.DES3Encrypt to a Java Function. My problem is that I don't get the same encrypted value in both scenes.
For this procedure in Oracle:
set serveroutput on;
declare
input raw(128);
encrypted raw(2048);
cadena varchar2(60);
begin
dbms_obfuscation_toolkit.DES3Encrypt(
input => utl_raw.cast_to_raw('TESTDATATESTDATATESTDATA'),
key => utl_raw.cast_to_raw('GD6GTT56HKY4HGF6FH3JG9J5F62FT1'),
encrypted_data => encrypted
);
dbms_output.put_line(rawtohex(encrypted));
end;
I get this output:
8A2E6792E39B0C850377F9A0E054033963F979E4A3FBA25B
However, with this Java class:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class TripleDes2
{
private static final String PLAIN_TEXT = "TESTDATATESTDATATESTDATA";
private static final String SHARED_KEY = "GD6GTT56HKY4HGF6FH3JG9J5F62FT1";
public static void main(String args []) throws Exception
{
String algorithm = "DESede";
String transformation = "DESede/CBC/PKCS5Padding";
byte[] keyValue = SHARED_KEY.getBytes("UTF-8");
DESedeKeySpec keySpec = new DESedeKeySpec(keyValue);
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
SecretKey key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
Cipher encrypter = Cipher.getInstance(transformation);
encrypter.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] input = PLAIN_TEXT.getBytes("UTF-8");
byte[] encrypted = encrypter.doFinal(input);
System.out.println(new String(Hex.encodeHex(encrypted)).toUpperCase());
}
}
I'm getting this value:
82EBC149F298DE55E4FF1540615E60ACDB7743FE79CD2CF4BB6FD232893F83D0
I'm not sure if my Java Code is right. Can you help me?
Thank you very much.
This is my final code, it works like a charm:
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
public class TripleDes3 {
private Cipher cipher = null;
private SecretKey key = null;
private byte[] bytes = null;
private IvParameterSpec iv = null;
public static void main(String[] args) throws Exception {
try {
String hexKey = "GD6GTT56HKY4HGF6FH3JG9J5";
//TripleDes3 encryptor = new TripleDes3(new String(Hex.decodeHex(hexKey.toCharArray())));
TripleDes3 encryptor = new TripleDes3(hexKey);
String original = "ABC";
System.out.println("Oringal: \"" + original + "\"");
String enc = encryptor.encrypt(original);
System.out.println("Encrypted: \"" + enc.toUpperCase() + "\"");
String dec = encryptor.decrypt(enc);
System.out.println("Decrypted: \"" + dec.toUpperCase() + "\"");
if (dec.equals(original)) {
System.out.println("Encryption ==> Decryption Successful");
}
} catch (Exception e) {
System.out.println("Error: " + e.toString());
}
}
public TripleDes3(String encryptionKey) throws GeneralSecurityException, DecoderException {
cipher = Cipher.getInstance("DESede/CBC/NoPadding");
try {
key = new SecretKeySpec(encryptionKey.getBytes("ISO8859_15"), "DESede");
iv = new IvParameterSpec(Hex.decodeHex("0123456789abcdef".toCharArray()));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String encrypt(String input) throws GeneralSecurityException, UnsupportedEncodingException {
bytes = input.getBytes("ISO8859_15");
bytes = Arrays.copyOf(bytes, ((bytes.length+7)/8)*8);
return new String(Hex.encodeHex(encryptB(bytes)));
}
public String decrypt(String input) throws GeneralSecurityException, DecoderException, UnsupportedEncodingException {
bytes = Hex.decodeHex(input.toCharArray());
String decrypted = new String(decryptB(bytes), "ISO8859_15");
if (decrypted.indexOf((char) 0) > 0) {
decrypted = decrypted.substring(0, decrypted.indexOf((char) 0));
}
return decrypted;
}
public byte[] encryptB(byte[] bytes) throws GeneralSecurityException {
cipher.init(Cipher.ENCRYPT_MODE, (Key) key, iv);
return cipher.doFinal(bytes);
}
public byte[] decryptB(byte[] bytes) throws GeneralSecurityException {
cipher.init(Cipher.DECRYPT_MODE, (Key) key, iv);
return cipher.doFinal(bytes);
}
}
And this is the Oracle Code:
DECLARE
v_data VARCHAR2(255);
v_retval RAW(255);
p_str VARCHAR2(255);
p_key RAW(255);
BEGIN
p_str := 'ABC';
p_key := utl_raw.cast_to_raw('GD6GTT56HKY4HGF6FH3JG9J5F62FT1');
v_data := RPAD(p_str, CEIL(LENGTH(p_str)/8)*8, CHR(0));
dbms_obfuscation_toolkit.DES3Encrypt
(
input => utl_raw.cast_to_raw(v_data),
key => p_key,
which => 1,
encrypted_data => v_retval
);
dbms_output.put_line(v_retval);
END;

What is wrong with this code?

Thanx to evry one help me ..but still there is 2 problem after editing the code
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4(){}
public static void main(String[] args)throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException{
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
**byte c[] = RCC4.encrypt(plain,b);**
**byte p[] = RCC4.decrypt(c,b);**
**System.out.println(new String(c)) ;
System.out.println(new String(p));**
}
public static byte[] encrypt(byte[] plaintext,byte[] keyBytes)
{
byte[] e = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher enCipher = Cipher.getInstance("RC4");
**enCipher.init(Cipher.ENCRYPT_MODE ,key);**
e = enCipher.doFinal(plaintext);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext,byte[] keyBytes)
{
byte de[] = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher deCipher = Cipher.getInstance("RC4");
**deCipher.init(Cipher.DECRYPT_MODE, key);**
de = deCipher.doFinal(ciphertext);
}
catch(Exception e)
{
e.printStackTrace();
}
return de;
}
public static Key getKey()
{
Key key = null;
try
{
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128,sr);
key = kg.generateKey();
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
public static String keyGet()
{
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}
When I press "Build file" it says process completed but at running file a message says
112670544188765215715791498302542646231
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.encrypt(RCC4.java:37)
at RCC4.main(RCC4.java:23)
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.decrypt(RCC4.java:53)
at RCC4.main(RCC4.java:24)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:479)
at RCC4.main(RCC4.java:26)
Process completed.
These Lines are indicated as *
Answer to original question:
Key key = new SecretKeySpec(byte[]keyBytes,RC4);
should be
Key key = new SecretKeySpec(keyBytes, "RC4");
Also,
deCipher.init(Cipher.WHATEVER, keyBytes);
should be
deCipher.init(Cipher.WHATEVER, key);
Then it compiles, however there's still some issue with the application logic. That's up to you again :).
Answer to new question:
The problem was the unneeded usage of SecretKeySpec. Somewhere between getKey(), keyGet() all the byte[] games and SecretKeySpec it got wrong somehow. I didn't have the patience to track it, so I just deleted it and made the code somewhat more readable to make sure I didn't miss anything. I think you will still understand it since it still is basically your code and it is much simpler now.
import java.security.*;
import javax.crypto.*;
public class RCC4 {
public static void main(String[] args) throws Exception {
String plain = "testisperfect";
Key key = RCC4.getKey();
String encrypted = RCC4.encrypt(plain, key);
String decrypted = RCC4.decrypt(encrypted, key);
System.out.println(encrypted);
System.out.println(decrypted);
}
private static String rc4(String plaintext, int mode, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(mode, key);
return new String(cipher.doFinal(plaintext.getBytes()));
}
public static String encrypt(String plaintext, Key key) throws Exception {
return rc4(plaintext, Cipher.ENCRYPT_MODE, key);
}
public static String decrypt(String ciphertext, Key key) throws Exception {
return rc4(ciphertext, Cipher.DECRYPT_MODE, key);
}
public static Key getKey() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("RC4");
SecureRandom sr = new SecureRandom();
kg.init(128, sr);
return kg.generateKey();
}
}
You need import SecretKeySpec which is under package javax.crypto.spec.
You're not calling the method correctly in that you're passing in the parameter type with the parameter. Parameter types are only shown when declaring a method, not when calling the method.
In other words, it's not
Key key = new SecretKeySpec(byte[] keyBytes, RC4);
it's instead
Key key = new SecretKeySpec(keyBytes, RC4);
You will of course need to have a keyBytes variable declared and initialized before trying to pass it into the parameter of this method.
package test;
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4() {
}
public static void main(String[] args) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IOException {
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
byte c[] = RCC4.encrypt(plain, b);
byte p[] = RCC4.decrypt(c, b);
System.out.println(new String(c));
System.out.println(new String(p));
}
public static byte[] encrypt(byte[] plaintext, byte[] keyBytes) {
byte[] e = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher enCipher = Cipher.getInstance("RC4");
enCipher.init(Cipher.ENCRYPT_MODE, key);
e = enCipher.doFinal(plaintext);
} catch (Exception ex) {
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext, byte[] keyBytes) {
byte de[] = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher deCipher = Cipher.getInstance("RC4");
deCipher.init(Cipher.DECRYPT_MODE, RCC4.getKey());
de = deCipher.doFinal(ciphertext);
} catch (Exception e) {
e.printStackTrace();
}
return de;
}
public static Key getKey() {
Key key = null;
try {
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128, sr);
key = kg.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
public static String keyGet() {
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}

Categories