How to encrypt & decrypt large video file - java

I would like to store video files in storage that can be accessed only my application. outside the user should not be able to access his video. I tried Encryption & Decryption but the video file is too large (1GB) it takes a lot of time.
Do you have any Idea guys how can I do?
Please find below my Encryption & Decryption Code :
private File sdCardRoot;
private ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sdCardRoot = Environment.getExternalStorageDirectory();
Button encrypt = findViewById(R.id.zip);
Button dencrypt = findViewById(R.id.unzip);
progressBar = findViewById(R.id.progress);
encrypt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
progressBar.setVisibility(View.VISIBLE);
try {
Log.e("file", "try");
encryption();
} catch (Exception e) {
Log.e("file", "catch" + String.valueOf(e));
e.printStackTrace();
}
}
});
dencrypt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
progressBar.setVisibility(View.VISIBLE);
try {
dcryption();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void dcryption() throws Exception {
progressBar.setVisibility(View.VISIBLE);
String password = "javapapers";
// reading the salt
// user should have secure mechanism to transfer the
// salt, iv and password to the recipient
File fileSalt = new File(sdCardRoot, "/salt.enc");
FileInputStream saltFis = new FileInputStream(fileSalt);
byte[] salt = new byte[8];
saltFis.read(salt);
saltFis.close();
// reading the iv
File fileIv = new File(sdCardRoot, "/iv.enc");
FileInputStream ivFis = new FileInputStream(fileIv);
byte[] iv = new byte[16];
ivFis.read(iv);
ivFis.close();
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536,
256);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
// file decryption
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
File oldFile = new File(sdCardRoot, "/wp.mp4");
File oldFile1 = new File(sdCardRoot, "/w.des");
FileInputStream fis = new FileInputStream(oldFile1);
FileOutputStream fos = new FileOutputStream(oldFile);
byte[] in = new byte[64];
int read;
while ((read = fis.read(in)) != -1) {
byte[] output = cipher.update(in, 0, read);
if (output != null)
fos.write(output);
}
byte[] output = cipher.doFinal();
if (output != null) {
fos.write(output);
fis.close();
fos.flush();
fos.close();
}
if (fileIv.exists() && fileSalt.exists() && oldFile1.exists()) {
fileIv.delete();
fileSalt.delete();
oldFile1.delete();
}
progressBar.setVisibility(View.GONE);
System.out.println("File Decrypted.");
}
private void encryption() throws Exception {
File oldFile = new File(sdCardRoot, "/w.mp4");
File oldFile1 = new File(sdCardRoot, "/w.des");
Log.e("file", String.valueOf(oldFile));
FileInputStream inFile = new FileInputStream(oldFile);
Log.e("file", String.valueOf(inFile));
// encrypted file
FileOutputStream outFile = new FileOutputStream(oldFile1);
Log.e("file", String.valueOf(outFile));
// password to encrypt the file
String password = "javapapers";
// password, iv and salt should be transferred to the other end
// in a secure manner
// salt is used for encoding
// writing it to a file
// salt should be transferred to the recipient securely
// for decryption
byte[] salt = new byte[8];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(salt);
Log.e("file", "a");
File fileSalt = new File(sdCardRoot, "/salt.enc");
FileOutputStream saltOutFile = new FileOutputStream(fileSalt);
Log.e("file", "b");
saltOutFile.write(salt);
saltOutFile.close();
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536,
256);
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
//
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
// iv adds randomness to the text and just makes the mechanism more
// secure
// used while initializing the cipher
// file to store the iv
Log.e("file", "c");
File fileIv = new File(sdCardRoot, "/iv.enc");
FileOutputStream ivOutFile = new FileOutputStream(fileIv);
Log.e("file", "d");
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
ivOutFile.write(iv);
ivOutFile.close();
//file encryption
byte[] input = new byte[64];
int bytesRead;
while ((bytesRead = inFile.read(input)) != -1) {
byte[] output = cipher.update(input, 0, bytesRead);
if (output != null)
outFile.write(output);
}
byte[] output = cipher.doFinal();
if (output != null)
outFile.write(output);
inFile.close();
outFile.flush();
outFile.close();
if (oldFile.exists()) {
oldFile.delete();
}
System.out.println("File Encrypted.");
}

Use Below Code:
import java.io.File;
import java.io.RandomAccessFile;
public class VideoCrypt {
public static final int REVERSE_BYTE_COUNT = 1024;
public static boolean decrypt(String path) {
try {
if (path == null) return false;
File source = new File(path);
int byteToReverse = source.length() < REVERSE_BYTE_COUNT ? ((int) source.length()) : REVERSE_BYTE_COUNT;
RandomAccessFile f = new RandomAccessFile(source, "rw");
f.seek(0);
byte b[] = new byte[byteToReverse];
f.read(b);
f.seek(0);
reverseBytes(b);
f.write(b);
f.seek(0);
b = new byte[byteToReverse];
f.read(b);
f.close();
return true;
} catch (Exception e) {
return false;
}
}
public static boolean encrypt(String path) {
try {
if (path == null) return false;
File source = new File(path);
RandomAccessFile f = new RandomAccessFile(source, "rw");
f.seek(0);
int byteToReverse = source.length() < REVERSE_BYTE_COUNT ? ((int) source.length()) : REVERSE_BYTE_COUNT;
byte b[] = new byte[byteToReverse];
f.read(b);
f.seek(0);
reverseBytes(b);
f.write(b);
f.seek(0);
b = new byte[byteToReverse];
f.read(b);
f.close();
return true;
} catch (Exception e) {
return false;
}
}
private static void reverseBytes(byte[] array) {
if (array == null) return;
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
}
}

File types are identified by file extension and file magic. If you want to skip encrypting the file you can edit the file header by changing its magic so that programs can't recognize the type. A "magic" is a few bytes at the start of the file that define its type.

Related

javax.crypto.BadPaddingException: Given final block not properly padded while decryption

I am trying to decrypt a file in java. The first 16 bytes of decrypted file are IV (initialization vector). Please help in resolving the above exception.
I am trying to prepend the IV in the output file in AESFileEncryption() and then reading it while decryption.
Thank You.
public class AESFileEncryption {
public static void encrypt(String path,String pwd) throws Exception {
FileOutputStream outFile;
try (
FileInputStream inFile = new FileInputStream(path)) {
String fileName=path;
System.out.println(path);
outFile = new FileOutputStream(fileName+".aes");
// password to encrypt the file
String password = pwd;
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128);// user-chosen password that can be used with password-based encryption (PBE).
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");//Secret KeySpec is a class and implements inteface SecretKey
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[16];
random.nextBytes(bytes);
IvParameterSpec ivspec = new IvParameterSpec(bytes);
cipher.init(Cipher.ENCRYPT_MODE, secret,ivspec);//opmode,key
outFile.write(bytes);
byte[] input = new byte[64];
int bytesRead;
while ((bytesRead = inFile.read(input)) != -1) {
byte[] output = cipher.update(input, 0, bytesRead);
if (output != null)
Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND);
} byte[] output = cipher.doFinal();
if (output != null)
Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND);
}
outFile.flush();
outFile.close();
File f=new File(path);
boolean x=f.delete();
if(x){
System.out.println("File deleted");
}
JOptionPane.showMessageDialog(null,"File Encrypted.");
}
}
Decryption code
public class AESFileDecryption {
public static void decrypt(String path,String pwd) throws Exception {
String password = pwd;
String fileName=path;
File file=new File(path);
//System.out.println(inFile.toString());
String fileNameWithOutExt = path.replaceFirst("[.][^.]+$", "");
System.out.println(fileName);
System.out.println(fileNameWithOutExt);
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
System.out.println("1");
FileInputStream fis = new FileInputStream(path);
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
System.out.println("2");
// file decryption
Cipher cipher=null;
byte bytes[]=new byte[16];
fis.read(bytes, 0, 16);
IvParameterSpec ivspec = new IvParameterSpec(bytes);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
System.out.println("3");
FileOutputStream fos = new FileOutputStream(fileNameWithOutExt);
System.out.println("4");
byte[] in = new byte[64];
int read;
while ((read = fis.read(in,16,(int)file.length()-16)) != -1) {
byte[] output = cipher.update(in, 0, read);
if (output != null)
fos.write(output);
}
try{
byte[] output = cipher.doFinal();
if (output != null)
fos.write(output);
fis.close();
fos.flush();
fos.close();
System.out.println("File Decrypted.");
}
catch(IOException | BadPaddingException | IllegalBlockSizeException e)
{
System.out.println(e+"");
}
}
}
There are a few problems with the small example, but the one that is most immediately your problem is the line
while ((read = fis.read(in,16,(int)file.length()-16)) != -1) {
You seem to be confused about the meaning of the offset parameter to the read(). It is not the offset into the file, but rather the offset into the array (in) that is specified in the first parameter.
A non-exhaustive list of other problems that I see include:
writing to the file using the two independent mechanisms (FileOutputStream.write() and Files.write()). This actually worked ok when I ran your program but it seems like it's asking for trouble. There's no reason to use Files.write() here.
fis.read(bytes, 0, 16); does not check the return value.
It seems you are struggling with finding some IO idioms that you're comfortable with. Or perhaps just experimenting. At the risk of giving you even more options to juggle, you might consider investigating google's open source Guava library. Many people find it has just what they needed.

javax.crypto.BadPaddingException: Given final block not properly padded while decrypting a file

I am trying to write a program to encrypt and decrypt files using java, but I get an error on the decrypt function:
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
here is the code for the encryption:
public static void EncryptFile(String inFile, PublicKey rsaPublicKey) {
AesManaged aesManaged = new AesManaged();
try {
aesManaged.keySize = 256;
aesManaged.blockSize = 128;
aesManaged.mode = "AES/CBC/PKCS5Padding";
byte[] key = generateKey(aesManaged.keySize);
byte[] keyEncrypted = encryptKey(key, rsaPublicKey);
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
int lKey = keyEncrypted.length;
LenK = BitConverter.GetBytes(lKey);
int lIV = aesManaged.IV().length;
LenIV = BitConverter.GetBytes(lIV);
// Write the following to the FileStream
// for the encrypted file (outFs):
// - length of the key
// - length of the IV
// - ecrypted key
// - the IV
// - the encrypted cipher content
String outFile = "test.lamar";
ByteArrayOutputStream outFs = new ByteArrayOutputStream();
outFs.write(LenK);
outFs.write(LenIV);
outFs.write(keyEncrypted);
byte[] i = aesManaged.IV();
outFs.write(i);
IvParameterSpec ivspec = new IvParameterSpec(aesManaged.IV());
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(aesManaged.mode);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivspec);
FileInputStream fileIn = new FileInputStream(inFile);
CipherOutputStream cipherOut = new CipherOutputStream(outFs, cipher);
int blockSiseByte = aesManaged.blockSize / 8;
byte[] data = new byte[blockSiseByte];
int count;
// Read in the data from the file and encrypt it
while ((count = fileIn.read(data, 0, blockSiseByte)) != -1) {
cipherOut.write(data, 0, count);
}
try (OutputStream outputStream = new FileOutputStream(outFile)) {
outFs.writeTo(outputStream);
}
// Close the encrypted file
fileIn.close();
outFs.close();
cipherOut.close();
} catch (Exception e) {
e.printStackTrace();
}
}
and the code for the decryption:
public static void DecryptFile(String inFile, String outFile,
PrivateKey rsaPrivateKey) {
FileOutputStream outFs = null;
try {
// Create instance of AesManaged for
// symetric decryption of the data.
AesManaged aesManaged = new AesManaged();
{
aesManaged.keySize = 256;
aesManaged.blockSize = 128;
aesManaged.mode = "AES/CBC/PKCS5Padding";
// Create byte arrays to get the length of
// the encrypted key and IV.
// These values were stored as 4 bytes each
// at the beginning of the encrypted package.
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
// Use FileStream objects to read the encrypted
// file (inFs) and save the decrypted file (outFs).
{
byte[] fileBytes = FileUtils.readFileToByteArray(new File(inFile));
ByteArrayInputStream inFs = new ByteArrayInputStream(
fileBytes);
;
for (int i = 0; i < LenK.length; i++) {
LenK[i] = (byte) inFs.read();
}
for(int i = 0; i< LenIV.length;i++){
LenIV[i] = (byte)inFs.read();
}
// Convert the lengths to integer values.
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
//int startC = lenK + lenIV + 8;
//int lenC = (int) fileBytes.length - startC;
// Create the byte arrays for
// the encrypted AesManaged key,
// the IV, and the cipher text.
byte[] KeyEncrypted = new byte[lenK];
byte[] IV = new byte[lenIV];
// Extract the key and IV
for(int i = 0;i<lenK;i++){
KeyEncrypted[i] = (byte)inFs.read();
}
for(int i =0;i<lenIV;i++){
IV[i] = (byte)inFs.read();
}
// to decrypt the AesManaged key.
byte[] KeyDecrypted = decryptKey(KeyEncrypted,rsaPrivateKey);
Cipher transform = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivspec = new IvParameterSpec(IV);
SecretKeySpec secretKeySpec = new SecretKeySpec(KeyDecrypted, "AES");
transform.init(Cipher.DECRYPT_MODE, secretKeySpec, ivspec);
// Decrypt the key.
outFs = new FileOutputStream(outFile);
int count = 0;
int offset = 0;
int blockSizeBytes = aesManaged.blockSize / 8;
byte[] data = new byte[blockSizeBytes];
CipherInputStream cipherIn = new CipherInputStream(
inFs, transform);
while ((count = cipherIn.read(data, 0, blockSizeBytes)) != -1) {
outFs.write(data, 0, count);
}
inFs.close();
cipherIn.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
The error occurred at the line:while ((count = cipherIn.read(data, 0, blockSizeBytes)) != -1) after many iterations.
What am I missing here?

Read public key from file

i am trying to verify a file with my java program. I have no idea what i am doing wrong, all the solutions i found does not work.
Here is my code:
public boolean pruefeSignatur(File file, File signatur, File publicKey) {
boolean verifies = false;
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// encode public key bytes
FileInputStream keyfis = new FileInputStream(publicKey);
byte [] encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
// key specification
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
// conversion
KeyFactory keyFactory = KeyFactory.getInstance(pubKeySpec.getFormat());
// generate publicKey
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
// input signature bytes
FileInputStream sigfis = new FileInputStream(signatur);
byte[] sigToVerify = new byte[sigfis.available()];
sigfis.read(sigToVerify);
sigfis.close();
// initialize the signature
Signature sig = Signature.getInstance("RSA");
sig.initVerify(pubKey);
// supply signature object with the data to be verified
FileInputStream datafis = new FileInputStream(file);
BufferedInputStream bufin = new BufferedInputStream(datafis);
byte[] buffer = new byte[1024];
int len;
while(bufin.available() != 0) {
len = bufin.read(buffer);
sig.update(buffer, 0, len);
}
bufin.close();
//verify signature
verifies = sig.verify(sigToVerify);
} catch (Exception e) {
e.printStackTrace();
}
return verifies;
}
With this code i get the exception:
java.security.spec.InvalidKeySpecException: java.lang.ClassCastException: org.bouncycastle.asn1.DERUnknownTag cannot be cast to org.bouncycastle.asn1.ASN1Object
When i use Base64, for example:
Base64 decoder = new Base64();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(decoder.decode(encKey));
I get the exception:
java.security.spec.InvalidKeySpecException: java.io.IOException: unexpected end-of-contents marker
Another solution i found was changing it to:
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
// conversion
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
But then i get the exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
I made my keys with Gpg4win and Kleopatra.
Edit:
Now I do not get an error, but the function always returns false. So I am not sure if everything is right.
public boolean pruefeSignatur(File file, File signaturFile, File publicKeyFile) throws IOException {
boolean verifies = false;
FileInputStream keyfis = null;
DataInputStream keydis = null;
FileInputStream sigfis = null;
DataInputStream sigdis = null;
FileInputStream datafis = null;
DataInputStream datadis = null;
try {
// add provider
Security.addProvider(new BouncyCastleProvider());
// encode public key bytes
keyfis = new FileInputStream(publicKeyFile);
keydis = new DataInputStream(keyfis);
byte[] keyBytes = new byte[(int) publicKeyFile.length()];
keydis.readFully(keyBytes);
keyfis.close();
keydis.close();
// key specification
String modulusBase64 = new String(keyBytes);
Base64 b64 = new Base64();
String exponentBase64 = "65337"; //festgelegte Zahl http://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(1, b64.decode(modulusBase64)), new BigInteger(1, b64.decode(exponentBase64)));
// conversion
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// generate publicKey
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
// read signature
sigfis = new FileInputStream(signaturFile);
sigdis = new DataInputStream(sigfis);
byte[] sigBytes = new byte[(int) signaturFile.length()];
sigdis.readFully(sigBytes);
sigfis.close();
sigdis.close();
// initialize the signature
Signature sig = Signature.getInstance("RSA");
sig.initVerify(publicKey);
// supply signature object with the data to be verified
datafis = new FileInputStream(file);
datadis = new DataInputStream(datafis);
byte[] dataBytes = new byte[(int) file.length()];
datadis.readFully(dataBytes);
/*
int len;
while(datadis.available() != 0) {
len = datadis.read(dataBytes);
sig.update(dataBytes, 0, len);
}
*/
datadis.close();
datafis.close();
sig.update(dataBytes);
//verify signature
verifies = sig.verify(sigBytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (keyfis != null) {
keyfis.close();
}
if (keydis != null) {
keydis.close();
}
if (sigfis != null) {
sigfis.close();
}
if (sigdis != null) {
sigdis.close();
}
if (datafis != null) {
datafis.close();
}
if (datadis != null) {
datadis.close();
}
}
return verifies;
}
Finally i have a solution:
InputStream inSig = PGPUtil.getDecoderStream(new FileInputStream(signaturFile));
//ArmoredInputStream inSig = new ArmoredInputStream(new FileInputStream(signaturFile));
JcaPGPObjectFactory objFactory = new JcaPGPObjectFactory(inSig);
PGPSignatureList signatureList = (PGPSignatureList) objFactory.nextObject();
PGPSignature signature = signatureList.get(0);
InputStream keyIn = PGPUtil.getDecoderStream(new FileInputStream(publicKeyFile));
//ArmoredInputStream keyIn = new ArmoredInputStream(new FileInputStream(publicKeyFile));
JcaPGPPublicKeyRingCollection pgpRing = new JcaPGPPublicKeyRingCollection(keyIn);
PGPPublicKey publicKey = pgpRing.getPublicKey(signature.getKeyID());
byte[] bytePublicKeyFingerprint = publicKey.getFingerprint();
char[] publicKeyFingerprintHexArray = org.apache.commons.codec.binary.Hex.encodeHex(bytePublicKeyFingerprint);
String publicKeyFingerprintHex = new String(publicKeyFingerprintHexArray);
signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey);
FileInputStream in = new FileInputStream(file);
byte[] byteData = new byte[(int) file.length()];
in.read(byteData);
in.close();
signature.update(byteData);
if (signature.verify() && publicKeyFingerprintHex.equals(fingerprint)) {
return true;
} else {
return false;
}

decrypting a file on server, checking its hash and digital signature and then encrypting it again and saving on file server

My application requires the users to upload digitally signed pdf and then encrypt the file. This encrypted file is then uploaded on server, where it is decrypted. The decrypted file is then verified by matching the hash of file and digital signature. Now this file is encrypted with using AES algorithm. Once encryption is completed the file is then stored on file server. The size of file could go upto 80mb.
The challenge I am facing now is that when the encrypted file is stored on local drive of machine the files get saved instantly but when the file server is on another machine it takes upto 30 min to save a single file. I am not able to figure out the reason for it.
Following is the code which I am using. I have deployed and tried in tomcat 6 and IBM WAS. The file transfer takes the same time when transferring to file server. The file server is connected to Application server via SAN network.
Following is my encryption code
strSymAlg = rb.getString("SYM_KEY_ALG"); //SYM_KEY_ALG=AES
cipher = Cipher.getInstance(strSymAlg);
SecKey = new SecretKeySpec(hex2Byte(sSymmetricKey), strSymAlg);
cipher.init(Cipher.DECRYPT_MODE, SecKey);
baos = recoverFile(new FileInputStream(fileEnv), cipher);
if (baos != null && isRecoveredFileValid((InputStream) new ByteArrayInputStream(baos.toByteArray()))) {
fileRecovered = (InputStream) new ByteArrayInputStream(baos.toByteArray());
}
}
private ByteArrayOutputStream recoverFile(FileInputStream in, Cipher cipher) {
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;
int outLength = 0;
boolean more = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
outLength = cipher.update(inBytes, 0, blockSize, outBytes);
baos.write(outBytes, 0, outLength);
} else {
more = false;
}
}
if (inLength > 0) {
outBytes = cipher.doFinal(inBytes, 0, inLength);
} else {
outBytes = cipher.doFinal();
}
baos.write(outBytes);
} catch (Exception e) {
System.out.println("recoverFile1: " + e.getMessage());
// e.printStackTrace();
baos = null;
}
return baos;
}
my encryption code is
String strSymKey = "";
File fileToCreate = null;
KeyGenerator keygen = KeyGenerator.getInstance(strSymAlg);
random = new SecureRandom();
keygen.init(random);
SecretKey secKey = keygen.generateKey();
Key publicKey = getPublicKeyFromString(sPubKey.trim());
//encrypt Symmetric key with public key
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.WRAP_MODE, publicKey);
byte[] wrappedKey = cipher.wrap(secKey);
strSymKey = byte2hex(wrappedKey);
fileToCreate = new File(strFile);
if (fileToCreate.exists()) {
fileToCreate.delete();
}
//Encrypt Bidder file with symmetric key
DataOutputStream out = new DataOutputStream(new FileOutputStream(strFile));
cipher = Cipher.getInstance(strSymAlg);
cipher.init(Cipher.ENCRYPT_MODE, secKey);
crypt(fis, out, cipher);
fis.close();
out.close();
//blnDone=true;
// System.out.println("STRING SYMMETRIC KEY:"+ strSymKey);
return strSymKey;
public String byte2hex(byte[] b) {
// String Buffer can be used instead
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
if (n < b.length - 1) {
hs = hs + "";
}
}
return hs;
}
New Function added
public void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException, GeneralSecurityException {
System.out.println("crypt start time :"+ new Date());
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
if (inLength > 0) {
outBytes = cipher.doFinal(inBytes, 0, inLength);
} else {
outBytes = cipher.doFinal();
}
System.out.println("crypt end time :"+ new Date());
out.write(outBytes);
}
Thanks in advance
You are making the classic mistake of assuming that every read fills the buffer, and another: that it won't do so at end of stream. Neither is correct.
while ((count = in.read(buffer)) >= 0)
{
out.write(cipher.update(buffer, 0, count));
}
out.write(cipher.doFinal());
You don't need a DataOutputStream for this.

Triple DES Encrypt C# - Decrypt in Java

I'm getting a Triple DES decrypted string from the clients server, which has been coded in c# (see below):
using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
var encryption = TripleDESEncrypt("12345678901234", "C9AF269DF8A78A06D1216BFFF8F0536A");
Console.WriteLine(encryption);
}
public static string TripleDESEncrypt(string strClearText, string strKey)
{
byte[] bytClearText;
byte[] bytClearTextChunk = new byte[8];
byte[] bytEncryptedChunk = new byte[8];
int BytesCount = 0;
int nArrayPosition = 0;
string strEncryptedChar;
string strEncryptedText = "";
ArrayList Input = new ArrayList();
ArrayList Output = new ArrayList();
TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();
tdes.Key = HexToByteArray(strKey);
tdes.Mode = CipherMode.ECB;
ICryptoTransform tdesEncrypt = tdes.CreateEncryptor();
bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
BytesCount = bytClearText.Length;
for (int i = 0; i < BytesCount; i++)
{
if (nArrayPosition == 8)
{
Input.Add(bytClearTextChunk);
bytClearTextChunk = new byte[8];
nArrayPosition = 0;
}
bytClearTextChunk[nArrayPosition] = bytClearText[i];
nArrayPosition++;
}
if (nArrayPosition != 0)
Input.Add(bytClearTextChunk);
foreach (byte[] Cbyte in Input)
{
tdesEncrypt.TransformBlock(Cbyte, 0, 8, bytEncryptedChunk, 0);
Output.Add(bytEncryptedChunk);
bytEncryptedChunk = null;
bytEncryptedChunk = new byte[8];
}
foreach (byte[] Cbyte in Output)
{
foreach (byte BByte in Cbyte)
{
strEncryptedChar = BByte.ToString("X");
strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
strEncryptedText += strEncryptedChar;
}
}
return strEncryptedText;
}
private static byte[] HexToByteArray(string strHex)
{
byte[] bytArray = new byte[strHex.Length / 2];
int positionCount = 0;
for (int i = 0; i < strHex.Length; i += 2)
{
bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
return bytArray;
}
}
I am then trying to Triple DES decrypt it in Java using this key: C9AF269DF8A78A06D1216BFFF8F0536A
Here is my code to decrypt:
public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
String UNICODE_FORMAT = "UTF8";
String decryptedPinText = null;
byte[] hexConvert = hexStringtoByteArray(encryptKey);
SecretKey desKey = null;
byte[] tdesKey = new byte[24];
System.arraycopy(hexConvert, 0, tdesKey, 0,16);
System.arraycopy(hexConvert, 0, tdesKey, 0,8);
byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);
KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
Cipher desCipher;
SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
try {
desKey = skf.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
desCipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] decryptPin = desCipher.doFinal(pin.getBytes());
decryptedPinText = new String(decryptPin, "UTF-8");
return decryptedPinText;
}
The sample out put would be input/output would be "12345678901234" however, I'm getting jumbled nonsense returned e.g ��0�8��/0��
So something is getting lost between c# and java...
This is a follow on from a previous question I asked here
I'd appreciate help on this
changes to code
public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
String UNICODE_FORMAT = "UTF8";
String decryptedPinText = null;
SecretKey desKey = null;
byte[] encryptKeyBytes = EncodingUtils.getAsciiBytes(encryptKey);
byte[] tdesKey = new byte[24];
System.arraycopy(encryptKeyBytes, 8, tdesKey, 0, 8);
System.arraycopy(encryptKeyBytes, 0, tdesKey, 8, 16);
KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
Cipher desCipher;
SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
try {
desKey = skf.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
desCipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] decryptPin = desCipher.doFinal(EncodingUtils.getAsciiBytes(pin));
decryptedPinText = new String(decryptPin, "ASCII");
return decryptedPinText;
}
c# decrypt code
using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
var encryption = TripleDESDecrypt("1D30CC3DE1641D7F5E821D13FC1200C3", "C9AF269DF8A78A06D1216BFFF8F0536A");
Console.WriteLine(encryption);
}
public static string TripleDESDecrypt(string strEncryptedText, string strKey)
{
string errorMessage = "";
int errorCode = 0;
string strDecryptedText = "";
try
{
byte[] bytEncryptedChunk = new byte[8];
byte[] bytClearTextChunk = new byte[8];
byte[] _bytesEmpty = new byte[8];
int BytesCount = 0;
int positionCount = 0;
ArrayList Input = new ArrayList();
ArrayList Output = new ArrayList();
TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();
tdes.Key = HexToByteArray(strKey);
tdes.Mode = CipherMode.ECB;
ICryptoTransform tdesDecrypt = tdes.CreateDecryptor();
BytesCount = strEncryptedText.Length;
for (int i = 0; i < BytesCount; i += 2)
{
if (positionCount == 8)
{
positionCount = 0;
Input.Add(bytEncryptedChunk);
bytEncryptedChunk = new byte[8];
}
bytEncryptedChunk[positionCount] = byte.Parse(strEncryptedText.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
if (positionCount != 0)
{
Input.Add(bytEncryptedChunk);
}
foreach (byte[] Cbyte in Input)
{
tdesDecrypt.TransformBlock(Cbyte, 0, 8, _bytesEmpty, 0);
tdesDecrypt.TransformBlock(Cbyte, 0, 8, bytClearTextChunk, 0);
Output.Add(bytClearTextChunk);
bytClearTextChunk = null;
bytClearTextChunk = new byte[8];
}
foreach (byte[] Cbyte in Output)
{
strDecryptedText += ASCIIEncoding.ASCII.GetString(Cbyte);
}
}
catch (Exception ex)
{
errorCode = 1;
errorMessage = ex.Message;
}
Console.WriteLine(strDecryptedText);
return strDecryptedText;
}
private static byte[] HexToByteArray(string strHex)
{
byte[] bytArray = new byte[strHex.Length / 2];
int positionCount = 0;
for (int i = 0; i < strHex.Length; i += 2)
{
bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
return bytArray;
}
}
This returns what is inputting into the encrypt 12345678901234
In your C# code, you use ASCII:
bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
While in Java you use UNICODE:
byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);
Try to change your C# to use UNICODE or your java code to use ASCII.
Also, since the C# is padding the output :
strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
You probably must check to remove all the '00' in the crypted string, so 1D30CC3DE1641D7F5E821D13FC1200C3 will become 1D30CC3DE1641D7F5E821D13FC12C3
(you must check if it's in the boundaries of an hex expression: 1C01A1 should probably be modified since it got a padding on the second Hexa 1C 01 A1: 1C1A1
acording https://stackoverflow.com/a/33768305/1140304 you can use
unicode instead of UTF-8 in java code
encrypt in c# :
public static string Encrypt2(string clearText,string key)
{
try
{
string encryptedText = "";
MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.KeySize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
byte[] ivBytes = new byte[8];
des.Key = md5Bytes;
des.IV = ivBytes;
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
ICryptoTransform ct = des.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
encryptedText = Convert.ToBase64String(ms.ToArray());
}
return encryptedText;
}
catch (Exception exception)
{
return "";
}
}
for decode in c# you can use:
public static string Decrypt2(string cipher,string key)
{
try
{
byte[] clearBytes = Convert.FromBase64String(cipher);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
string encryptedText = "";
TripleDES des = new TripleDESCryptoServiceProvider();
des.KeySize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
byte[] ivBytes = new byte[8];
des.Key = md5Bytes;
des.IV = ivBytes;
ICryptoTransform ct = des.CreateDecryptor();
byte[] resultArray = ct.TransformFinalBlock(clearBytes, 0, clearBytes.Length);
encryptedText = Encoding.Unicode.GetString(resultArray);
return encryptedText;
}
catch (Exception exception)
{
return "";
}
}
now, for encrypt in java you can use :
private String _encrypt2(String clearText,String key )
{
try
{
/**
* create md5
*/
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; )
{
keyBytes[k++] = keyBytes[j++];
}
SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] plainTextBytes = clearText.getBytes("UTF-16LE");
byte[] cipherText = cipher.doFinal(plainTextBytes);
String output = Base64.encodeToString(cipherText,Base64.DEFAULT);
return output;
}
catch (Exception ex) {}
return "";
}
and for decrypt in java :
private String _decrypt2(String encryptText,String key)
{
MessageDigest md = null;
byte[] digestOfPassword = null;
try
{
byte[] message = Base64.decode(encryptText.getBytes("UTF-16LE"), Base64.DEFAULT);
/**
* make md5
*/
md = MessageDigest.getInstance("md5");
digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; )
{
keyBytes[k++] = keyBytes[j++];
}
SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] cipherText = cipher.doFinal(message);
return new String(cipherText, "UTF-16LE");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (InvalidKeyException e)
{
e.printStackTrace();
}
catch (InvalidAlgorithmParameterException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
catch (BadPaddingException e)
{
e.printStackTrace();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace();
}
return "";
}
If someone find himself/herself in the same problem like I did, here is a java implementation (android) of the same .NET decrypt function:
public static byte[] byteArrayConcat(byte[] array1, byte[] array2) {
byte[] result = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, result, 0, array1.length);
System.arraycopy(array2, 0, result, array1.length, array2.length);
return result;
}
private byte[] fGPKeyTo3DESKey(byte[] GPKey) {
byte[] _3DESKey = new byte[24];
byte[] tmp = new byte[8];
arraycopy(GPKey, 0, tmp, 0, 8);
_3DESKey = DaPlugUtils.byteArrayConcat(GPKey, tmp);
return _3DESKey;
}
private static byte[] hexStringtoByteArray(String hex) {
int len = hex.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
}
return data;
}
public String desDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException {
int bytesCount = 0;
int positionCount = 0;
byte[] bytEncryptedChunk = new byte[8];
ArrayList<byte[]> Input = new ArrayList();
bytesCount = pin.length();
for (int i = 0; i < bytesCount; i += 2) {
if (positionCount == 8) {
positionCount = 0;
Input.add(bytEncryptedChunk);
bytEncryptedChunk = new byte[8];
}
bytEncryptedChunk[positionCount] = (byte) (Integer.parseInt(pin.substring(i, i + 2), 16));
positionCount++;
}
if (positionCount != 0) {
Input.add(bytEncryptedChunk);
}
byte[] _3DESKey = fGPKeyTo3DESKey(hexStringtoByteArray(encryptKey));
DESedeKeySpec keySpec = new DESedeKeySpec(_3DESKey);
SecretKey k = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, k);
String res = "";
for (byte[] bs : Input) {
byte[] decryptPin = cipher.doFinal(bs);
String a = new String(decryptPin, StandardCharsets.US_ASCII);
res += a;
}
return res.trim();
}

Categories