Related
We have the application done C# and passing parameter to Java application. To make it secure we Java application developer come up with AES encryption. The developer gave sample code in Java. Kindly somebody helps me. How can I encrypt same way in C#
// Cryptix imports
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import cryptix.provider.key.RawSecretKey;
import cryptix.util.core.Hex;
import xjava.security.Cipher;
public class AESEncryption {
private Cipher m_alg;
private RawSecretKey m_key;
private static final String RIJNDAEL = "Rijndael"; //mode of encryption
private static final String PROVIDER_CRYPTIX = "Cryptix"; // Cryptography algorithm providers
/**
* Must (once) be dynamically installed. - could alternatively be set
* statically in $JAVAHOME/lib/security by changing security provider.
*
*/
static {
java.security.Security.addProvider(new cryptix.provider.Cryptix());
System.out.println(" Java Security - Add security provider - Cryptix provider added");
}
public AESEncryption(String secretKey)
throws java.security.NoSuchProviderException, java.security.NoSuchAlgorithmException {
//System.out.println("Key used for encryption/decryption :- " + secretKey);
m_alg = Cipher.getInstance(RIJNDAEL, PROVIDER_CRYPTIX);
m_key = new RawSecretKey(RIJNDAEL, Hex.fromString(secretKey));
}
/**
* encrypt supplied string.
*
* #param str to encrypted
* #return encrypted String
*/
public String encrypt(String str) throws java.security.KeyException {
byte[] ect = null;
str = convert(str); // pad if necessary
//System.out.println("String to encrypt [ " + str + " ]");
m_alg.initEncrypt(m_key);
ect = m_alg.crypt(str.getBytes());
//System.out.println("Encrypted String [ " + Hex.toString(ect) + " ]");
return Hex.toString(ect);
}
public String decrypt(String str) throws java.security.KeyException {
byte[] dct = null;
String decryptedString;
//System.out.println("String to decrypt [ " + str + " ]");
m_alg.initDecrypt(m_key);
dct = m_alg.crypt(Hex.fromString(str));
decryptedString = new String(dct);
//System.out.println("Decrypted String [ " + decryptedString + " ]");
return decryptedString.trim();
}
/**
* Internal routine to convert a string to a byte array and to
* pad the byte array (with 0) in order ot fill out the final block.
*
* padding value based on Cipher's defined block size.
*
* #param str
* #return
*/
private String convert(String str) {
int padding = 0, sourceLength = 0, i, blockSize;
sourceLength = str.length();
blockSize = m_alg.blockSize();
padding = blockSize - (sourceLength % blockSize);
if (padding != blockSize) {
for (i = 0; i < padding; i++) {
str = str + " ";
}
}
return str;
}
public static void main(String[] args) {
try {
AESEncryption tcase = new AESEncryption("27323A0825226DDD316881852610DACB81210355C3117DAD83EF5EE9E8602915");
String params ="accentué";
System.out.println("Params Before:" + params);
String encrypted = tcase.encrypt(params);
System.out.println("Params Encrypted:" + encrypted);
String enc = "E669500CF68CCD88CBA54EDAA07E30A57E8C8518101D0D7C36323194222D6B4393AC2B22A914E902F47C89BC0CE1BCE67A14066219C3480875E1D75536AE0009899C23E644F0C701AE6EBB4DB0C1EDCF9A3A7FFA9BE117237083B5EC4B4EE7FBEBB94D7526C4C9E23EA38E2B2B526E8005265817FC505974DACAA55D3AA50FCE3440BFE79447135D071443DAE4013F2C32CDA00F4AFC2194B616FA50A1BF688F53336194B156E709818DD323F574CDA83A0716F7C22572278D9C162DC8DBC000AEF4C972E6FD203706CFFBE6143130CEB78D4F1CD77B64352766A9C2885AF66B1F81C11A4C71B2B1BF662AD854D429A8356B8FD91B1083ACDAD1DDE3BFF1353D108E2E133558324E63EE9DC13CB4B34BEE494C674BC7BB8C7E77B936AB16BC320E303A34B7510A438C9A9D7E212C3CA3F6771A7DD0CC1AB8A9D1B89FD850B343C7E8828A0155C1A30FA78B250EB073000C9D4F39EA8BF6AE8C19A0BA32EC222DF4BC59396F2396E4FBAB4599EE28E63F068E33614CF84D98D1FEF504E5DCC5940CF17294B6910845A9DDD8805833E1DB1C3CBF0658D1388A65546D58CE465E0E4FA941B6635E1A7042048C1B64456C3EAF9D331E3889E55E37CE71201C7B34526FF2C9297E52F7CBCC7603809566AE4AE3AE644BA826A130DA71DD201532C564F0B11E17306DF061DCF74AD6062931AD09D75345B11933D293945557755788E5C39D1485E87B8C20ED983EA977B9D9CDD7D8E3112D858061A6C376FB37A4E6292B0E4640A05A850175382E385F7F095CAFED9DFCBBEA6C10AA571EE8D01D6022CC240CCDD22EA374D619B4191F619DFB574EBFA80BAEC393F7FCD111789C96AA3DFA1E58E60EEB712F4C4A41506E38A7BF9CF24BFDEF2B7FE6E25C1D9ADAC11EA3CCF6F187A7446A9933D4C4BB25DE8467592D2457F7674E13D087B47221C0EBB8716F312FF52E46EA77566364346D2D899228F0C99737C4AD2A95C9CF892F89430CA1EEEFA68CE85321E5A4A44E71B6C4C62C8D3623E6103D9638A7DC0E66A249F130365773A3530F8F8F1FC4C57B4BEC296C1A0DD190646F2F3A427DE54155E6772FADF7A09488F45AE7CBA9C2F90BD3205D97E00C8CF62AB5FBEC774CA457A38E351FF110B8AA799918AE93E864862EE2F3B5D997D6C249613283337D83A60BDF3490BB73EB2A948A71D61E433F58A537693364D131DD7787D4D4A9C6EE891AB5B783A4F7B6009127D72A1F184ADA2BE20647EB6FE15FACDDF43A03BA9FE120E552A2BA14F568D65187C1F2E6108699C405018A3447A149C0A5196504201677E37CE789246D48A5270B59597D9F77F75E7CF23B18B51D5F25E37258BB231CE0E9FD3E5B21D14F1541A76F4875F231038751A36A79C84C4EBF9F2146506EC8DF6EBDD0CFECCBF388D9020CC5656322BF695D3ED716FAF0545040830815B550075F5D2301C6469F5DD99E5FD0093C4A";
//String decrypted = tcase.decrypt(encrypted);
String decrypted = tcase.decrypt(enc);
System.out.println("Params Decrypted:" + decrypted);
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (java.security.KeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
İf you used IV vector in c# while encrypted data with AES . You should use IV vector in Java
c#
using (var random = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
var key = new byte[16];
random.GetBytes(key);
using (System.Security.Cryptography.AesCryptoServiceProvider aesAlg = new System.Security.Cryptography.AesCryptoServiceProvider())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 128;
aesAlg.Key = key;
aesAlg.IV = key;
aesAlg.Mode = System.Security.Cryptography.CipherMode.CBC;
aesAlg.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
using (ICryptoTransform iCryptoper = aesAlg.CreateEncryptor())
{
byte[] encryptedData = iCryptoper.TransformFinalBlock(x509CertData, 0, x509CertData.Length);
string encodedCert = Convert.ToBase64String(encryptedData);
System.Security.Cryptography.X509Certificates.X509Certificate2 x509Cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(x509CertData);
System.Security.Cryptography.RSACryptoServiceProvider provider = (System.Security.Cryptography.RSACryptoServiceProvider)x509Cert.PublicKey.Key;
byte[] encrypted = provider.Encrypt(aesAlg.Key, false);
string test = Convert.ToBase64String(encrypted);
}
}
}
java
javax.crypto.SecretKey sc = new javax.crypto.spec.SecretKeySpec(secretKey, "AES");
Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
dcipher.init(Cipher.DECRYPT_MODE, sc, ivParameterSpec);
byte[] decyrptedCert = dcipher.doFinal(java.util.Base64.getDecoder().decode(stringToDecrypt));
In my web application I am asking user to upload the files. I am reading that file and converting it into byte array like this
byte[] fileContent =new byte[(int)uploadedFile.length()];
FileInputStream fin=new FileInputStream(uploadedFile);
fin.read(fileContent);
Now I encrypt this byte array using AES encryption with the password supplies by the user. I am using this library to encrypt. After encryption I am saving this byte array into hibernate database. I have this filed in my Files entity class.
#Lob
#Basic(fetch=FetchType.LAZY)
#Column(name = "filedata", columnDefinition = "LONGBLOB")
private byte[] fileData;
I am saving this by save method
session=sessionFactory.openSession();
session.beginTransaction();
session.save(f);
session.getTransaction().commit();
session.close();
When I retrive the file from database I use get method
session=sessionFactory.openSession();
session.beginTransaction();
cr=session.createCriteria(Files.class);
Files f=(Files) cr.add(Restrictions.eq("fid", fid)).uniqueResult();
session.getTransaction().commit();
session.close();
After retrieving I am decrypting the byte array that is in the File object but I am getting Input file is corrupt error. I understand this error is because the byte array has changed from saving to getting.
What would be the solution to this issue. I want the user to supply password for encrypting and decrypting. I am using MySql database at the backend.
EDITS: AESCrypt class
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.NetworkInterface;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Enumeration;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.stereotype.Repository;
/**
* This class provides methods to encrypt and decrypt files using
* aescrypt file format,
* version 1 or 2.
* <p>
* Requires Java 6 and <a href="http://java.sun.com/javase/downloads/index.jsp">Java
* Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files</a>.
* <p>
* Thread-safety and sharing: this class is not thread-safe.<br>
* <tt>AESCrypt</tt> objects can be used as Commands (create, use once and dispose),
* or reused to perform multiple operations (not concurrently though).
*
*/
#Repository
public final class AESCrypt {
private static final String JCE_EXCEPTION_MESSAGE = "Please make sure "
+ "\"Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files\" "
+ "(http://java.sun.com/javase/downloads/index.jsp) is installed on your JRE.";
private static final String RANDOM_ALG = "SHA1PRNG";
private static final String DIGEST_ALG = "SHA-256";
private static final String HMAC_ALG = "HmacSHA256";
private static final String CRYPT_ALG = "AES";
private static final String CRYPT_TRANS = "AES/CBC/NoPadding";
private static final byte[] DEFAULT_MAC =
{0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (byte) 0xcd, (byte) 0xef};
private static final int KEY_SIZE = 32;
private static final int BLOCK_SIZE = 16;
private static final int SHA_SIZE = 32;
private final boolean DEBUG;
private byte[] password;
private Cipher cipher;
private Mac hmac;
private SecureRandom random;
private MessageDigest digest;
private IvParameterSpec ivSpec1;
private SecretKeySpec aesKey1;
private IvParameterSpec ivSpec2;
private SecretKeySpec aesKey2;
/*******************
* PRIVATE METHODS *
*******************/
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
* #param message
*/
protected void debug(String message) {
if (DEBUG) {
System.out.println("[DEBUG] " + message);
}
}
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
* #param message
* #param bytes
*/
protected void debug(String message, byte[] bytes) {
if (DEBUG) {
StringBuilder buffer = new StringBuilder("[DEBUG] ");
buffer.append(message);
buffer.append("[");
for (int i = 0; i < bytes.length; i++) {
buffer.append(bytes[i]);
buffer.append(i < bytes.length - 1 ? ", " : "]");
}
System.out.println(buffer.toString());
}
}
/**
* Generates a pseudo-random byte array.
* #param len
* #return pseudo-random byte array of <tt>len</tt> bytes.
*/
protected byte[] generateRandomBytes(int len) {
byte[] bytes = new byte[len];
random.nextBytes(bytes);
return bytes;
}
/**
* SHA256 digest over given byte array and random bytes.<br>
* <tt>bytes.length</tt> * <tt>num</tt> random bytes are added to the digest.
* <p>
* The generated hash is saved back to the original byte array.<br>
* Maximum array size is {#link #SHA_SIZE} bytes.
* #param bytes
* #param num
*/
protected void digestRandomBytes(byte[] bytes, int num) {
assert bytes.length <= SHA_SIZE;
digest.reset();
digest.update(bytes);
for (int i = 0; i < num; i++) {
random.nextBytes(bytes);
digest.update(bytes);
}
System.arraycopy(digest.digest(), 0, bytes, 0, bytes.length);
}
/**
* Generates a pseudo-random IV based on time and this computer's MAC.
* <p>
* This IV is used to crypt IV 2 and AES key 2 in the file.
* #return IV.
*/
protected byte[] generateIv1() {
byte[] iv = new byte[BLOCK_SIZE];
long time = System.currentTimeMillis();
byte[] mac = null;
try {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (mac == null && ifaces.hasMoreElements()) {
mac = ifaces.nextElement().getHardwareAddress();
}
} catch (Exception e) {
// Ignore.
}
if (mac == null) {
mac = DEFAULT_MAC;
}
for (int i = 0; i < 8; i++) {
iv[i] = (byte) (time >> (i * 8));
}
System.arraycopy(mac, 0, iv, 8, mac.length);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates an AES key starting with an IV and applying the supplied user password.
* <p>
* This AES key is used to crypt IV 2 and AES key 2.
* #param iv
* #param password
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey1(byte[] iv, byte[] password) {
byte[] aesKey = new byte[KEY_SIZE];
System.arraycopy(iv, 0, aesKey, 0, iv.length);
for (int i = 0; i < 8192; i++) {
digest.reset();
digest.update(aesKey);
digest.update(password);
aesKey = digest.digest();
}
return aesKey;
}
/**
* Generates the random IV used to crypt file contents.
* #return IV 2.
*/
protected byte[] generateIV2() {
byte[] iv = generateRandomBytes(BLOCK_SIZE);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates the random AES key used to crypt file contents.
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey2() {
byte[] aesKey = generateRandomBytes(KEY_SIZE);
digestRandomBytes(aesKey, 32);
return aesKey;
}
/**
* Utility method to read bytes from a stream until the given array is fully filled.
* #param in
* #param bytes
* #throws IOException if the array can't be filled.
*/
protected void readBytes(InputStream in, byte[] bytes) throws IOException {
if (in.read(bytes) != bytes.length) {
throw new IOException("Unexpected end of file");
}
}
/**************
* PUBLIC METHODS *
**************/
/**
* Builds an object to encrypt or decrypt files with the given password.
* #param password
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(String password) throws GeneralSecurityException, UnsupportedEncodingException {
this(false, password);
}
/**
* Builds an object to encrypt or decrypt files with the given password.
* #param debug
* #param password
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(boolean debug, String password) throws GeneralSecurityException, UnsupportedEncodingException {
try {
DEBUG = debug;
setPassword(password);
random = SecureRandom.getInstance(RANDOM_ALG);
digest = MessageDigest.getInstance(DIGEST_ALG);
cipher = Cipher.getInstance(CRYPT_TRANS);
hmac = Mac.getInstance(HMAC_ALG);
} catch (GeneralSecurityException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* Changes the password this object uses to encrypt and decrypt.
* #param password
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public void setPassword(String password) throws UnsupportedEncodingException {
this.password = password.getBytes("UTF-16LE");
debug("Using password: ", this.password);
}
/**
* The file at <tt>fromPath</tt> is encrypted and saved at <tt>toPath</tt> location.
* <p>
* <tt>version</tt> can be either 1 or 2.
* #param version
* #param fromPath
* #param toPath
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
encrypt(version, in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is encrypted and saved to the output stream.
* <p>
* <tt>version</tt> can be either 1 or 2.<br>
* None of the streams are closed.
* #param version
* #param in
* #param out
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null;
ivSpec1 = new IvParameterSpec(generateIv1());
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
ivSpec2 = new IvParameterSpec(generateIV2());
aesKey2 = new SecretKeySpec(generateAESKey2(), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
out.write("AES".getBytes("UTF-8")); // Heading.
out.write(version); // Version.
out.write(0); // Reserved.
if (version == 2) { // No extensions.
out.write(0);
out.write(0);
}
out.write(ivSpec1.getIV()); // Initialization Vector.
text = new byte[BLOCK_SIZE + KEY_SIZE];
cipher.init(Cipher.ENCRYPT_MODE, aesKey1, ivSpec1);
cipher.update(ivSpec2.getIV(), 0, BLOCK_SIZE, text);
cipher.doFinal(aesKey2.getEncoded(), 0, KEY_SIZE, text, BLOCK_SIZE);
out.write(text); // Crypted IV and key.
debug("IV2 + AES2 ciphertext: ", text);
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
text = hmac.doFinal(text);
out.write(text); // HMAC from previous cyphertext.
debug("HMAC1: ", text);
cipher.init(Cipher.ENCRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
text = new byte[BLOCK_SIZE];
int len, last = 0;
while ((len = in.read(text)) > 0) {
cipher.update(text, 0, BLOCK_SIZE, text);
hmac.update(text);
out.write(text); // Crypted file data block.
last = len;
}
last &= 0x0f;
out.write(last); // Last block size mod 16.
debug("Last block size mod 16: " + last);
text = hmac.doFinal();
out.write(text); // HMAC from previous cyphertext.
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* The file at <tt>fromPath</tt> is decrypted and saved at <tt>toPath</tt> location.
* <p>
* The input file can be encrypted using version 1 or 2 of aescrypt.<br>
* #param fromPath
* #param toPath
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
decrypt(new File(fromPath).length(), in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is decrypted and saved to the output stream.
* <p>
* The input file size is needed in advance.<br>
* The input stream can be encrypted using version 1 or 2 of aescrypt.<br>
* None of the streams are closed.
* #param inSize
* #param in
* #param out
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(long inSize, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null, backup = null;
long total = 3 + 1 + 1 + BLOCK_SIZE + BLOCK_SIZE + KEY_SIZE + SHA_SIZE + 1 + SHA_SIZE;
int version;
text = new byte[3];
readBytes(in, text); // Heading.
if (!new String(text, "UTF-8").equals("AES")) {
throw new IOException("Invalid file header");
}
version = in.read(); // Version.
if (version < 1 || version > 2) {
throw new IOException("Unsupported version number: " + version);
}
debug("Version: " + version);
in.read(); // Reserved.
if (version == 2) { // Extensions.
text = new byte[2];
int len;
do {
readBytes(in, text);
len = ((0xff & (int) text[0]) << 8) | (0xff & (int) text[1]);
if (in.skip(len) != len) {
throw new IOException("Unexpected end of extension");
}
total += 2 + len;
debug("Skipped extension sized: " + len);
} while (len != 0);
}
text = new byte[BLOCK_SIZE];
readBytes(in, text); // Initialization Vector.
ivSpec1 = new IvParameterSpec(text);
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
cipher.init(Cipher.DECRYPT_MODE, aesKey1, ivSpec1);
backup = new byte[BLOCK_SIZE + KEY_SIZE];
readBytes(in, backup); // IV and key to decrypt file contents.
debug("IV2 + AES2 ciphertext: ", backup);
text = cipher.doFinal(backup);
ivSpec2 = new IvParameterSpec(text, 0, BLOCK_SIZE);
aesKey2 = new SecretKeySpec(text, BLOCK_SIZE, KEY_SIZE, CRYPT_ALG);
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
backup = hmac.doFinal(backup);
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC1: ", text);
total = inSize - total; // Payload size.
if (total % BLOCK_SIZE != 0) {
throw new IOException("Input file is corrupt");
}
if (total == 0) { // Hack: empty files won't enter block-processing for-loop below.
in.read(); // Skip last block size mod 16.
}
debug("Payload size: " + total);
cipher.init(Cipher.DECRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
backup = new byte[BLOCK_SIZE];
text = new byte[BLOCK_SIZE];
for (int block = (int) (total / BLOCK_SIZE); block > 0; block--) {
int len = BLOCK_SIZE;
if (in.read(backup, 0, len) != len) { // Cyphertext block.
throw new IOException("Unexpected end of file contents");
}
cipher.update(backup, 0, len, text);
hmac.update(backup, 0, len);
if (block == 1) {
int last = in.read(); // Last block size mod 16.
debug("Last block size mod 16: " + last);
len = (last > 0 ? last : BLOCK_SIZE);
}
out.write(text, 0, len);
}
out.write(cipher.doFinal());
backup = hmac.doFinal();
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
}
Finally solved it. This code was triggering the exception.
total = inSize - total; // Payload size.
if (total % BLOCK_SIZE != 0) {
throw new IOException("Input file is corrupt");
}
Apparently I was passing the inSize parameter as file size but after encryption the file size increases by roughly about 134 bytes. So that modulus doesn't come out zero. I have checked the original, encrypted, the data that was passed to hibernate and the data that hibernate returns there is no single point of conflict. The hibernate returns the same byte data when I retrieve it using get or criteria that was passed at the time of saving into database.
Hope this helps others who are trying to use AES encryption and decryption along with hibernate.
I am using AESCrypt open source library to encrypt file. This is my code
String password="asdfgh";
String frompath=new String("C:/Users/sabertooth/Desktop/error/pnberror.png");
String topath=new String("C:/Users/sabertooth/desktop/error/");
AESCrypt aes=new AESCrypt(false,password);
aes.encrypt(2, frompath, topath);
I am geeting access denied exception. Here is the stacktrace
Exception in thread "main" java.io.FileNotFoundException: C:\Users\sabertooth\desktop\error (Access is denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:104)
at AESCrypt.encrypt(AESCrypt.java:284)
at NewClass.main(NewClass.java:28)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
Posting the code for aescrypt.java
/*
* Copyright 2008 Vócali Sistemas Inteligentes
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.NetworkInterface;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Enumeration;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This class provides methods to encrypt and decrypt files using
* aescrypt file format,
* version 1 or 2.
* <p>
* Requires Java 6 and <a href="http://java.sun.com/javase/downloads/index.jsp">Java
* Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files</a>.
* <p>
* Thread-safety and sharing: this class is not thread-safe.<br>
* <tt>AESCrypt</tt> objects can be used as Commands (create, use once and dispose),
* or reused to perform multiple operations (not concurrently though).
*
* #author Vócali Sistemas Inteligentes
*/
public class AESCrypt {
private static final String JCE_EXCEPTION_MESSAGE = "Please make sure "
+ "\"Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files\" "
+ "(http://java.sun.com/javase/downloads/index.jsp) is installed on your JRE.";
private static final String RANDOM_ALG = "SHA1PRNG";
private static final String DIGEST_ALG = "SHA-256";
private static final String HMAC_ALG = "HmacSHA256";
private static final String CRYPT_ALG = "AES";
private static final String CRYPT_TRANS = "AES/CBC/NoPadding";
private static final byte[] DEFAULT_MAC =
{0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (byte) 0xcd, (byte) 0xef};
private static final int KEY_SIZE = 32;
private static final int BLOCK_SIZE = 16;
private static final int SHA_SIZE = 32;
private final boolean DEBUG;
private byte[] password;
private Cipher cipher;
private Mac hmac;
private SecureRandom random;
private MessageDigest digest;
private IvParameterSpec ivSpec1;
private SecretKeySpec aesKey1;
private IvParameterSpec ivSpec2;
private SecretKeySpec aesKey2;
/*******************
* PRIVATE METHODS *
*******************/
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
*/
protected void debug(String message) {
if (DEBUG) {
System.out.println("[DEBUG] " + message);
}
}
/**
* Prints a debug message on standard output if DEBUG mode is turned on.
*/
protected void debug(String message, byte[] bytes) {
if (DEBUG) {
StringBuilder buffer = new StringBuilder("[DEBUG] ");
buffer.append(message);
buffer.append("[");
for (int i = 0; i < bytes.length; i++) {
buffer.append(bytes[i]);
buffer.append(i < bytes.length - 1 ? ", " : "]");
}
System.out.println(buffer.toString());
}
}
/**
* Generates a pseudo-random byte array.
* #return pseudo-random byte array of <tt>len</tt> bytes.
*/
protected byte[] generateRandomBytes(int len) {
byte[] bytes = new byte[len];
random.nextBytes(bytes);
return bytes;
}
/**
* SHA256 digest over given byte array and random bytes.<br>
* <tt>bytes.length</tt> * <tt>num</tt> random bytes are added to the digest.
* <p>
* The generated hash is saved back to the original byte array.<br>
* Maximum array size is {#link #SHA_SIZE} bytes.
*/
protected void digestRandomBytes(byte[] bytes, int num) {
assert bytes.length <= SHA_SIZE;
digest.reset();
digest.update(bytes);
for (int i = 0; i < num; i++) {
random.nextBytes(bytes);
digest.update(bytes);
}
System.arraycopy(digest.digest(), 0, bytes, 0, bytes.length);
}
/**
* Generates a pseudo-random IV based on time and this computer's MAC.
* <p>
* This IV is used to crypt IV 2 and AES key 2 in the file.
* #return IV.
*/
protected byte[] generateIv1() {
byte[] iv = new byte[BLOCK_SIZE];
long time = System.currentTimeMillis();
byte[] mac = null;
try {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (mac == null && ifaces.hasMoreElements()) {
mac = ifaces.nextElement().getHardwareAddress();
}
} catch (Exception e) {
// Ignore.
}
if (mac == null) {
mac = DEFAULT_MAC;
}
for (int i = 0; i < 8; i++) {
iv[i] = (byte) (time >> (i * 8));
}
System.arraycopy(mac, 0, iv, 8, mac.length);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates an AES key starting with an IV and applying the supplied user password.
* <p>
* This AES key is used to crypt IV 2 and AES key 2.
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey1(byte[] iv, byte[] password) {
byte[] aesKey = new byte[KEY_SIZE];
System.arraycopy(iv, 0, aesKey, 0, iv.length);
for (int i = 0; i < 8192; i++) {
digest.reset();
digest.update(aesKey);
digest.update(password);
aesKey = digest.digest();
}
return aesKey;
}
/**
* Generates the random IV used to crypt file contents.
* #return IV 2.
*/
protected byte[] generateIV2() {
byte[] iv = generateRandomBytes(BLOCK_SIZE);
digestRandomBytes(iv, 256);
return iv;
}
/**
* Generates the random AES key used to crypt file contents.
* #return AES key of {#link #KEY_SIZE} bytes.
*/
protected byte[] generateAESKey2() {
byte[] aesKey = generateRandomBytes(KEY_SIZE);
digestRandomBytes(aesKey, 32);
return aesKey;
}
/**
* Utility method to read bytes from a stream until the given array is fully filled.
* #throws IOException if the array can't be filled.
*/
protected void readBytes(InputStream in, byte[] bytes) throws IOException {
if (in.read(bytes) != bytes.length) {
throw new IOException("Unexpected end of file");
}
}
/**************
* PUBLIC API *
**************/
/**
* Builds an object to encrypt or decrypt files with the given password.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(String password) throws GeneralSecurityException, UnsupportedEncodingException {
this(false, password);
}
/**
* Builds an object to encrypt or decrypt files with the given password.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public AESCrypt(boolean debug, String password) throws GeneralSecurityException, UnsupportedEncodingException {
try {
DEBUG = debug;
setPassword(password);
random = SecureRandom.getInstance(RANDOM_ALG);
digest = MessageDigest.getInstance(DIGEST_ALG);
cipher = Cipher.getInstance(CRYPT_TRANS);
hmac = Mac.getInstance(HMAC_ALG);
} catch (GeneralSecurityException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* Changes the password this object uses to encrypt and decrypt.
* #throws UnsupportedEncodingException if UTF-16 encoding is not supported.
*/
public void setPassword(String password) throws UnsupportedEncodingException {
this.password = password.getBytes("UTF-16LE");
debug("Using password: ", this.password);
}
/**
* The file at <tt>fromPath</tt> is encrypted and saved at <tt>toPath</tt> location.
* <p>
* <tt>version</tt> can be either 1 or 2.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
encrypt(version, in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is encrypted and saved to the output stream.
* <p>
* <tt>version</tt> can be either 1 or 2.<br>
* None of the streams are closed.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void encrypt(int version, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null;
ivSpec1 = new IvParameterSpec(generateIv1());
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
ivSpec2 = new IvParameterSpec(generateIV2());
aesKey2 = new SecretKeySpec(generateAESKey2(), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
out.write("AES".getBytes("UTF-8")); // Heading.
out.write(version); // Version.
out.write(0); // Reserved.
if (version == 2) { // No extensions.
out.write(0);
out.write(0);
}
out.write(ivSpec1.getIV()); // Initialization Vector.
text = new byte[BLOCK_SIZE + KEY_SIZE];
cipher.init(Cipher.ENCRYPT_MODE, aesKey1, ivSpec1);
cipher.update(ivSpec2.getIV(), 0, BLOCK_SIZE, text);
cipher.doFinal(aesKey2.getEncoded(), 0, KEY_SIZE, text, BLOCK_SIZE);
out.write(text); // Crypted IV and key.
debug("IV2 + AES2 ciphertext: ", text);
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
text = hmac.doFinal(text);
out.write(text); // HMAC from previous cyphertext.
debug("HMAC1: ", text);
cipher.init(Cipher.ENCRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
text = new byte[BLOCK_SIZE];
int len, last = 0;
while ((len = in.read(text)) > 0) {
cipher.update(text, 0, BLOCK_SIZE, text);
hmac.update(text);
out.write(text); // Crypted file data block.
last = len;
}
last &= 0x0f;
out.write(last); // Last block size mod 16.
debug("Last block size mod 16: " + last);
text = hmac.doFinal();
out.write(text); // HMAC from previous cyphertext.
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/**
* The file at <tt>fromPath</tt> is decrypted and saved at <tt>toPath</tt> location.
* <p>
* The input file can be encrypted using version 1 or 2 of aescrypt.<br>
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(String fromPath, String toPath)
throws IOException, GeneralSecurityException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(fromPath));
debug("Opened for reading: " + fromPath);
out = new BufferedOutputStream(new FileOutputStream(toPath));
debug("Opened for writing: " + toPath);
decrypt(new File(fromPath).length(), in, out);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
/**
* The input stream is decrypted and saved to the output stream.
* <p>
* The input file size is needed in advance.<br>
* The input stream can be encrypted using version 1 or 2 of aescrypt.<br>
* None of the streams are closed.
* #throws IOException when there are I/O errors.
* #throws GeneralSecurityException if the platform does not support the required cryptographic methods.
*/
public void decrypt(long inSize, InputStream in, OutputStream out)
throws IOException, GeneralSecurityException {
try {
byte[] text = null, backup = null;
long total = 3 + 1 + 1 + BLOCK_SIZE + BLOCK_SIZE + KEY_SIZE + SHA_SIZE + 1 + SHA_SIZE;
int version;
text = new byte[3];
readBytes(in, text); // Heading.
if (!new String(text, "UTF-8").equals("AES")) {
throw new IOException("Invalid file header");
}
version = in.read(); // Version.
if (version < 1 || version > 2) {
throw new IOException("Unsupported version number: " + version);
}
debug("Version: " + version);
in.read(); // Reserved.
if (version == 2) { // Extensions.
text = new byte[2];
int len;
do {
readBytes(in, text);
len = ((0xff & (int) text[0]) << 8) | (0xff & (int) text[1]);
if (in.skip(len) != len) {
throw new IOException("Unexpected end of extension");
}
total += 2 + len;
debug("Skipped extension sized: " + len);
} while (len != 0);
}
text = new byte[BLOCK_SIZE];
readBytes(in, text); // Initialization Vector.
ivSpec1 = new IvParameterSpec(text);
aesKey1 = new SecretKeySpec(generateAESKey1(ivSpec1.getIV(), password), CRYPT_ALG);
debug("IV1: ", ivSpec1.getIV());
debug("AES1: ", aesKey1.getEncoded());
cipher.init(Cipher.DECRYPT_MODE, aesKey1, ivSpec1);
backup = new byte[BLOCK_SIZE + KEY_SIZE];
readBytes(in, backup); // IV and key to decrypt file contents.
debug("IV2 + AES2 ciphertext: ", backup);
text = cipher.doFinal(backup);
ivSpec2 = new IvParameterSpec(text, 0, BLOCK_SIZE);
aesKey2 = new SecretKeySpec(text, BLOCK_SIZE, KEY_SIZE, CRYPT_ALG);
debug("IV2: ", ivSpec2.getIV());
debug("AES2: ", aesKey2.getEncoded());
hmac.init(new SecretKeySpec(aesKey1.getEncoded(), HMAC_ALG));
backup = hmac.doFinal(backup);
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC1: ", text);
total = inSize - total; // Payload size.
if (total % BLOCK_SIZE != 0) {
throw new IOException("Input file is corrupt");
}
if (total == 0) { // Hack: empty files won't enter block-processing for-loop below.
in.read(); // Skip last block size mod 16.
}
debug("Payload size: " + total);
cipher.init(Cipher.DECRYPT_MODE, aesKey2, ivSpec2);
hmac.init(new SecretKeySpec(aesKey2.getEncoded(), HMAC_ALG));
backup = new byte[BLOCK_SIZE];
text = new byte[BLOCK_SIZE];
for (int block = (int) (total / BLOCK_SIZE); block > 0; block--) {
int len = BLOCK_SIZE;
if (in.read(backup, 0, len) != len) { // Cyphertext block.
throw new IOException("Unexpected end of file contents");
}
cipher.update(backup, 0, len, text);
hmac.update(backup, 0, len);
if (block == 1) {
int last = in.read(); // Last block size mod 16.
debug("Last block size mod 16: " + last);
len = (last > 0 ? last : BLOCK_SIZE);
}
out.write(text, 0, len);
}
out.write(cipher.doFinal());
backup = hmac.doFinal();
text = new byte[SHA_SIZE];
readBytes(in, text); // HMAC and authenticity test.
if (!Arrays.equals(backup, text)) {
throw new IOException("Message has been altered or password incorrect");
}
debug("HMAC2: ", text);
} catch (InvalidKeyException e) {
throw new GeneralSecurityException(JCE_EXCEPTION_MESSAGE, e);
}
}
/* public static void main(String[] args) {
try {
if (args.length < 4) {
System.out.println("AESCrypt e|d password fromPath toPath");
return;
}
AESCrypt aes = new AESCrypt(true, args[1]);
switch (args[0].charAt(0)) {
case 'e':
aes.encrypt(2, args[2], args[3]);
break;
case 'd':
aes.decrypt(args[2], args[3]);
break;
default:
System.out.println("Invalid operation: must be (e)ncrypt or (d)ecrypt.");
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}
There is a method encrypt which takes 3 arguments version frompath topath
You can't write to a folder. And C:/Users/sabertooth/desktop/error/ is a folder path.
Also, new String("...") is unnecessary. Just use "...".
I wanted to know how to encrypt a file or a photo which will eventually uploaded into the dropbox.
As i have research online and only manage to found this code (pasted at the bottom) which only encrypt the password, but I wanted to know how to encrypt a file or a photo which will eventually uploaded into the dropbox instead.
So is there any reference or help or guide on how to write a java programming ( will be using on Eclipse software ) on encrypting a file using triple DES? Thank you so much.
package com.kushal.utils;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class DESEncryption {
private static final String UNICODE_FORMAT = "UTF8";
public static final String DES_ENCRYPTION_SCHEME = "DES";
private KeySpec myKeySpec;
private SecretKeyFactory mySecretKeyFactory;
private Cipher cipher;
byte[] keyAsBytes;
private String myEncryptionKey;
private String myEncryptionScheme;
SecretKey key;
public DESEncryption() throws Exception
{
myEncryptionKey = "ThisIsSecretEncryptionKey";
myEncryptionScheme = DES_ENCRYPTION_SCHEME;
keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
myKeySpec = new DESKeySpec(keyAsBytes);
mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = mySecretKeyFactory.generateSecret(myKeySpec);
}
/**
* Method To Encrypt The String
*/
public String encrypt(String unencryptedString) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
BASE64Encoder base64encoder = new BASE64Encoder();
encryptedString = base64encoder.encode(encryptedText);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
/**
* Method To Decrypt An Ecrypted String
*/
public String decrypt(String encryptedString) {
String decryptedText=null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
BASE64Decoder base64decoder = new BASE64Decoder();
byte[] encryptedText = base64decoder.decodeBuffer(encryptedString);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText= bytes2String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
/**
* Returns String From An Array Of Bytes
*/
private static String bytes2String(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
stringBuffer.append((char) bytes[i]);
}
return stringBuffer.toString();
}
/**
* Testing the DES Encryption And Decryption Technique
*/
public static void main(String args []) throws Exception
{
DESEncryption myEncryptor= new DESEncryption();
String stringToEncrypt="Sanjaal.com";
String encrypted=myEncryptor.encrypt(stringToEncrypt);
String decrypted=myEncryptor.decrypt(encrypted);
System.out.println("String To Encrypt: "+stringToEncrypt);
System.out.println("Encrypted Value :" + encrypted);
System.out.println("Decrypted Value :"+decrypted);
}
}
File reading is taken from here
public static byte[] encryptFile(String pFilePath, byte[] pKey) throws GeneralSecurityException, IOException
{
File file = new File(pFilePath);
long length = file.length();
InputStream is = new FileInputStream(file);
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Close the input stream and return bytes
is.close();
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
SecretKeyFactory lDESedeKeyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey kA = lDESedeKeyFactory.generateSecret(new DESedeKeySpec(pKey));
IvParameterSpec lIVSpec = new IvParameterSpec(new byte[8]);
Cipher desedeCBCCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
desedeCBCCipher.init(Cipher.ENCRYPT_MODE, kA, lIVSpec);
byte[] encrypted = desedeCBCCipher.doFinal(bytes);
return encrypted;
}
A file can probably be read as a string of binary digits (lots of 1's and 0's). You could read the file, then encrypt the string using DES the same way you would a password, outputting the result to a new file.
Decryption would work the same way, reading the encrypted file, decrypting, and outputting to an unencrypted file.
In the decrypt class, I cant get it to correctly decrypt. I've verified in the decrypt class that my salt and my ciphertext still carries the same values before I convert them back to bytes.
The program itself doesn't given an error however when I compile, I'll encrypt, save it to the string encryptPhrase and then decrypt it in the decrypt method and I cant seem to get it to decrypt properly. I've marked in comments where the issue is and gives a badpadding exception, however there is no padding?
The odd thing is... if i take out everything in the decrypt method and return just encryptPhrase, it actually returns the correct plain text.
Any help would be appreciated. Thanks! :)
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
public class PasswordEncryption {
private static int ITERATIONS = 1000;
private static String saltString;
private static String ciphertextString;
private static String encryptPhrase;
private static void usage(){
System.err.println("Usage: java PBE -e|-d password text");
System.exit(1);
}
public static void main(String[] args) throws Exception{
scan = new Scanner(System.in);
System.out.println("Please enter plain text: ");
String text = scan.nextLine();
System.out.println("Please enter password to encrypt plain text: ");
char [] pw = scan.nextLine().toCharArray();
int option=3;
while (option!=0){
System.out.println("Are we encrypting(1) or decrypting(2) or Exit(0)? " );
option = scan.nextInt();
String output="exiting program";
if (option == 1)
output = encrypt(pw, text);
else if (option ==2)
output = decrypt(pw,text);
System.out.println("Output: " +output);
}
}
private static Scanner scan;
private static String encrypt(char[] password, String plaintext) throws Exception {
//create random salt
byte[] salt = new byte[8];
SecureRandom random = new SecureRandom();
random.nextBytes(salt);
//create key based on password
int iterationCount = ITERATIONS;
PBEKeySpec pbeSpec = new PBEKeySpec(password, salt, iterationCount);
SecretKeyFactory keyFact = SecretKeyFactory.getInstance("PBEWithSHAAnd3KeyTripleDES");
//create a cipher
Cipher myCipher = Cipher.getInstance("PBEWithSHAAnd3KeyTripleDES");
Key encryptKey = keyFact.generateSecret(pbeSpec);
myCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
byte[] cipherText = myCipher.doFinal();
System.out.println("Encrypted Text: " +toString(cipherText));
//produce salt to string
saltString = salt.toString();
System.out.println("SALT: " +saltString);
//produce cipher text to string
ciphertextString = toString(cipherText);
//stores salt and cipher string in encryptPhrase
encryptPhrase = saltString+ciphertextString;
return saltString+ciphertextString;
}
public static String decrypt(char[] password, String encryptPhrase) throws Exception{
//split the encryption data into salt and ciphertext
//System.out.println("encrypt Phrase: " +encryptPhrase);
//convert salt into bytearray
byte[] bsalt = toByteArray(saltString);
//convert ciphertext into bytearray
byte[] bciphert= toByteArray(ciphertextString);
//produce cipher
/////////////////////////////////////////////////////////////////////
int iterationCount = ITERATIONS;
PBEKeySpec pbeSpec = new PBEKeySpec(password, bsalt, iterationCount);
//use SHA and 3DES
//create the key
SecretKeyFactory keyFact = SecretKeyFactory.getInstance("PBEWithSHAAnd3KeyTripleDES");
Cipher cDec = Cipher.getInstance("PBEWithSHAAnd3KeyTripleDES");
Key sKey = keyFact.generateSecret(pbeSpec);
//perform decryption
cDec.init(cDec.DECRYPT_MODE,sKey);
byte [] plainTextb = cDec.doFinal(bciphert); //gives me an error here. Says BadPaddingException: pad block corrupted?
String plainText = toString(plainTextb);
return plainText;
//return encryptPhrase;
}
/**
* Convert a byte array of 8 bit characters into a String.
*
*#param bytes the array containing the characters
* #param length the number of bytes to process
* #return a String representation of bytes
*/
public static String toString(byte[] bytes, int length)
{
char[] chars = new char[length];
for (int i = 0; i != chars.length; i++)
{
chars[i] = (char)(bytes[i] & 0xff);
}
return new String(chars);
}
/**
* Convert a byte array of 8 bit characters into a String.
*
* #param bytes the array containing the characters
* #return a String representation of bytes
*/
public static String toString( byte[] bytes)
{
return toString(bytes, bytes.length);
}
/**
* Convert the passed in String to a byte array by
* taking the bottom 8 bits of each character it contains.
*
* #param string the string to be converted
* #return a byte array representation
*/
public static byte[] toByteArray(String string)
{
byte[] bytes = new byte[string.length()];
char[] chars = string.toCharArray();
for (int i = 0; i != chars.length; i++)
{
bytes[i] = (byte)chars[i];
}
return bytes;
}
private static String digits = "0123456789abcdef";
public static String toHex(byte[] data, int length)
{
StringBuffer buf = new StringBuffer();
for (int i=0; i!= length; i++)
{
int v = data[i] & 0xff;
buf.append(digits.charAt(v >>4));
buf.append(digits.charAt(v & 0xf));
}
return buf.toString();
}
/**
* Return the passed in byte array as a hex string.
*
* #param data the bytes to be converted.
* #return a hex representation of data.
*/
public static String toHex(byte[] data)
{
return toHex(data, data.length);
}
}
Yet another confusion between bytes and characters. Could have guessed. Please look up the base 64 encoding and see why it exists. Then note the implementation of Object.toString() and lookup character encoding (don't use new String(byte[]) on randomized bytes).