I am using the following code to decrypt files encrypted from android device.
private void mDecrypt_File(FileInputStream fin, String outFile) throws Exception {
FileOutputStream fout = new FileOutputStream(outFile);
byte[] iv = new byte[16];
byte[] salt = new byte[16];
byte[] len = new byte[8];
byte[] FC_TAGBuffer = new byte[8];
Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE);
DataInputStream dis = new DataInputStream(fin);
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(DEFAULT_PASSWORD, salt, F_ITERATIONS);
SecretKey key = new SecretKeySpec(rfc.getBytes(32), "AES");
//decryption code
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
CipherInputStream cIn = new CipherInputStream(dis, cipher);
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
byte[] tempFC_TAGBuffer = changeByteArray(FC_TAGBuffer, 0);//new byte[8];
BigInteger ulong = new BigInteger(1, tempFC_TAGBuffer);
if (!ulong.equals(FC_TAG)) {
Exception ex = new Exception("Tags are not equal");
throw ex;
}
byte[] bytes = new byte[BUFFER_SIZE];
//determine number of reads to process on the file
long numReads = lSize / BUFFER_SIZE;
// determine what is left of the file, after numReads
long slack = (long) lSize % BUFFER_SIZE;
int read = -1;
int value = 0;
int outValue = 0;
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
// read the buffer_sized chunks
for (int i = 0; i < numReads; ++i) {
read = cIn.read(bytes, 0, bytes.length);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
// now read the slack
if (slack > 0) {
read = cIn.read(bytes, 0, (int) slack);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
fout.flush();
fout.close();
byte[] curHash = md.digest();
byte[] oldHash = new byte[md.getDigestLength()];
read = cIn.read(oldHash, 0, oldHash.length);
if (oldHash.length != read || (!CheckByteArrays(oldHash, curHash))) {
Exception ex = new Exception("File Corrupted!");
throw ex;
}
if (outValue != lSize) {
Exception ex = new Exception("File Sizes don't match!");
throw ex;
}
}
This code is working fine on android but behaving strange on Java desktop application.
What I have observed is, on reading old hash from CipherInputStream cIn returns correct hash value only if the size of data to be decrypted is multiples of 32. For example, if I encrypt a text file which have a text of length 32 chars(or 64/128/...), then the following code
byte[] oldHash = new byte[md.getDigestLength()];
read = cIn.read(oldHash, 0, oldHash.length);
if (oldHash.length != read || (!CheckByteArrays(oldHash, curHash))) {
Exception ex = new Exception("File Corrupted!");
throw ex;
}
calculates oldHash correctly, but if I change the text of any other length(not multiple of 32) then the oldHash's last few values becomes zeros.
My Observations :
Text Size 6 char - Trailing zeros in oldHash - 6
Text Size 13 char - Trailing zeros in oldHash - 13
Text Size 20 char - Trailing zeros in oldHash - 4
Text Size 32 char - Trailing zeros in oldHash - 0 // Correct Result
Text Size 31 char - Trailing zeros in oldHash - 1
Text Size 64 char - Trailing zeros in oldHash - 0 // Correct Result
Please help me understanding this behavior.
Agree with DuncanJones, your loop is a mess. Although you properly check the return value of the read() method your loop iterations assume that every read() will return BUFFER_SIZE bytes or 'slack' bytes for the last read.
You code would be hugely better if you make proper use of DataInputStream. For example, you wrap the FileInputStream fin in a DataInputStream but then use the wrong methods in these two lines:
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
instead, you should use the readFully method, as in:
dis.readFully(iv);
dis.readFully(salt);
Similarly, you would benefit from wrapping your CipherInputStream cIn with another DataInputStream, something like:
CipherInputStream cIn = new CipherInputStream(dis, cipher);
DataInputStream dcIn = new DataInputStream(cIn);
DataInputStream already has a getLong method, so you could just replace these lines:
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
with
long lSize = dcIn.getLong()
dcIn.readFully(FC_TAGBuffer);
and you get to throw out your homegrown getLong method. Now you can go on and read the next lSize bytes in exactly BUFFER_SIZE chunks using dcIn.readFully(bytes) and make your code, cleaner, shorter, easier to read, and correct.
Related
I have to encrypt a file line by line using the RC4 algorithm.
Encrypting the whole file and decrypting the whole file yields the original which is fine.
When I attempt to read the file one line at a time,encrypt it and then write the encrypted line to file, decryption of the resulting file yields just one correct line which is the first line of the original file.
I have tried to read the file and feed it to rc4 routine using a byte array whose size is a multiple of the key length but the results were the same. Here is my attempt:
try
{
BufferedReader br = new BufferedReader((new FileReader(fileToEncrypt)));
FileOutputStream fos = new FileOutputStream("C:\\Users\\nikaselo\\Documents\\Encryption\\encrypted.csv", true);
File file = new File("C:\\Users\\nikaselo\\Documents\\Encryption\\encrypted.csv");
// encrypt
while ((line = br.readLine()) != null)
{
byte [] encrypt = fed.RC4(line.getBytes(), pwd);
if (encrypt != null) dos.write(encrypt);
fos.flush();
}
fos.close();
// test decrypt
FileInputStream fis = null;
fis = new FileInputStream(file);
byte[] input = new byte[512];
int bytesRead;
while ((bytesRead = fis.read(input)) != -1)
{
byte [] de= fed.RC4(input, pwd);
String result = new String(de);
System.out.println(result);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
and here is my RC4 function
public byte [] RC4 (byte [] Str, String Pwd) throws Exception
{
int[] Sbox = new int [256] ;
int A, B,c,Tmp;;
byte [] Key = {};
byte [] ByteArray = {};
//KEY
if ((Pwd.length() == 0 || Str.length == 0))
{
byte [] arr = {};
return arr;
}
if(Pwd.length() > 256)
{
Key = Pwd.substring(0, 256).getBytes();
}
else
{
Key = Pwd.getBytes();
}
//String
for( A = 0 ; A <= 255; A++ )
{
Sbox[A] = A;
}
A = B = c= 0;
for (A = 0; A <= 255; A++)
{
B = (B + Sbox[A] + Key[A % Pwd.length()]) % 256;
Tmp = Sbox[A];
Sbox[A] = Sbox[B];
Sbox[B] = Tmp;
}
A = B = c= 0;
ByteArray = Str;
for (A = 0; A <= Str.length -1 ; A++)
{
B = (B + 1) % 256;
c = (c + Sbox[B]) % 256;
Tmp = Sbox[B];
Sbox[B] = Sbox[c];
Sbox[c] = Tmp;
ByteArray[A] = (byte) (ByteArray[A] ^ (Sbox[(Sbox[B] + Sbox[c]) % 256]));
}
return ByteArray;
}
Running this gives me one clean line and the rest is just unreadable.
You are encrypting line by line, but you are trying to decrypt in 512 bytes blocks.
Your options, as I see it are:
Encrypt and decrypt in fixed sized blocks
Pad each line out to 512 bytes (and split lines that are longer than 512 bytes)
Introduce a delimiter. This will be tricky because potentially any delimiter could appear in the cipher text, so you should base64 encode each encrypted line and separate them with line feeds.
Probably 1 is the easiest (and the one used in real encryption), but if you have to do it line by line, I would go with 3 even though this introduces a vulnerability, but it's RC4 which is no longer considered secure anyway.
I have problem with decryption (or maybe wrong encryption, too) of data with RSA in Java.
I wanna encrypt public key with some more info in String and then decrypt this public key and encrypt with it something (I use 2048 RSA):
Encryption:
public void saveExportToFile(String fileName, BigInteger mod, BigInteger exp, String info, PublicKey puk) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(baos));
try {
oout.writeObject(mod);
oout.writeObject(exp);
oout.writeChars(info);
oout.close();
baos.close();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, puk);
FileOutputStream fos = new FileOutputStream(new File(fileName));
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] data = baos.toByteArray();
int i = 0;
byte[] buffer = new byte[128];
byte[] cipherData = null;
while (i < data.length) {
if (i+128 >= data.length) {
buffer = new byte[data.length - i];
System.arraycopy(data, i, buffer, 0, data.length - i);
cipherData = cipher.doFinal(buffer);
bos.write(cipherData);
} else {
System.arraycopy(data, i, buffer, 0, 128);
cipherData = cipher.doFinal(buffer);
bos.write(cipherData);
}
i += 128;
}
bos.close();
} catch (Exception e) {
throw new IOException("Unexpected error", e);
}
}
Decryption:
public void getDataFromRSA(String sendname, PrivateKey privateKey) {
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(sendname)));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int length = 0;
int allLength = 0;
byte[] buffer = new byte[128];
byte[] bufferAC = null;
byte[] outData = null;
byte[] allData = null;
byte[] tmpData = null;
while ( (length = bis.read(buffer)) != -1) {
if (length < 128) {
bufferAC = new byte[length];
System.arraycopy(buffer, 0, bufferAC, 0, length);
outData = cipher.doFinal(bufferAC);
} else {
outData = cipher.doFinal(buffer); // HERE IS THE ERROR
}
allLength += outData.length;
tmpData = allData;
allData = new byte[allLength];
System.arraycopy(tmpData, 0, allData, 0, tmpData.length);
System.arraycopy(outData, 0, allData, tmpData.length, outData.length);
}
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | ClassNotFoundException | InvalidKeySpecException e) {
e.printStackTrace();
}
}
EDIT
OK, it seems I don't know about encryption as much as I thought. I'd like to use only RSA (if it's possible) since I don't need to transfer info more than once (size of info vary). I've edited encryption like this:
int i = 0;
byte[] buffer = new byte[245];
byte[] cipherData = null;
while (i < data.length) {
if (i+245 >= data.length) {
buffer = new byte[data.length - i];
System.arraycopy(data, i, buffer, 0, data.length - i);
} else {
System.arraycopy(data, i, buffer, 0, 245);
}
cipherData = cipher.update(buffer);
bos.write(cipherData);
i += 245;
}
bos.write(cipher.doFinal()); // HERE IS THE ERROR
bos.close();
And now I get javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes (tried several lower values for buffer size). Is it because data length is not multiple of blocksize? Could this be fixed? Thanks for answers.
First of all, you should be using hybrid encryption, i.e. first encrypt the data using a symmetric cipher and then encrypt the random secret with an RSA key - sending both to the receiver.
Second, you should never have to perform doFinal in a loop for a single message. Use update and a single doFinal instead.
And thirdly, 2048 bits is 256 bytes. As long as you keep trying to decrypt 128 bytes instead of 256, you will get this exception. Usually I use 2048 / Byte.SIZE instead, it makes the code more readable and will avoid mistakes.
This exception occurs when you try to encrypt data with private key and decrypt with public key, you need to reverse this or you have to use a single key to encrypt and decrypt your data. This would solve this exception.
this is
Long number = 0x001122334455667788L;
i need create byte[] of last 6 bytes of Long.
So its will be look like
byte[] bytes = {0x22,0x33,0x44,0x55,0x66,0x77,0x88};
What is the right way to make something like this?
Thanks for any responnse
byte[] buffer = new byte[6];
buffer[0] = (byte)(v >>> 40);
buffer[1] = (byte)(v >>> 32);
buffer[2] = (byte)(v >>> 24);
buffer[3] = (byte)(v >>> 16);
buffer[4] = (byte)(v >>> 8);
buffer[5] = (byte)(v >>> 0);
That's how DataOutputStream.writeLong() does (except it writes all the bytes, or course)
You can use a ByteBuffer
Long number = 0x001122334455667788L;
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.putLong(number);
byte[] full = buffer.array();
byte[] shorter = Arrays.copyOfRange(full, 2, 8); // get only the lower 6
How about using DataOutputStream?
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // This will be handy.
DataOutputStream os = new DataOutputStream(baos);
try {
os.writeLong(number); // Write our number.
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
os.close(); // close it.
} catch (IOException e) {
e.printStackTrace();
}
}
return Arrays.copyOfRange(baos.toByteArray(), 2, 8); // Copy out the last 6 elements.
A BigInteger will do it too.
BigInteger number = new BigInteger("001122334455667788", 16);
byte[] b = number.toByteArray();
// May need to tweak the `b.length - 6` if the number is less than 6 bytes long.
byte[] shortened = Arrays.copyOfRange(b, b.length - 6, b.length);
System.out.println(Arrays.toString(shortened));
java.lang.BigInteger toByteArray()
I am decrypting an XML file from the file system using Bouncy Castle. I output the decrypted text and get a fatal error SAXParseException on the very last byte of data. Below is my decryption method and the setup of the cipher object.
I was initially using cipher streams, and everything worked perfect (commented out code was my stream). Due to policy files and end users not having the 256 bit unlimited versions I need to use bouncy castle.
Any ideas why the final byte is not coming through?
From Constructor:
keyParam = new KeyParameter(key);
engine = new AESEngine();
paddedBufferedBlockCipher =
new PaddedBufferedBlockCipher(new CBCBlockCipher(engine));
Decrypt Method:
public void decrypt(InputStream in, OutputStream out) {
try
{
paddedBufferedBlockCipher.init(false,
new ParametersWithIV(keyParam, _defaultIv));
// cipher.init(Cipher.DECRYPT_MODE, secretKey, ivs);
// CipherInputStream cipherInputStream
// = new CipherInputStream(in, cipher);
byte[] buffer = new byte[4096];
byte[] outBuffer = new byte[4096];
for (int count = 0; (count = in.read(buffer)) != -1;) {
paddedBufferedBlockCipher.processBytes(buffer, 0,
count, outBuffer, 0);
out.write(outBuffer, 0, count);
}
}
catch(Exception e) {
e.printStackTrace();
}
}
[Fatal Error] :40:23: Element type "Publi" must be followed by either attribute specifications, ">" or "/>".
org.xml.sax.SAXParseException: Element type "Publi" must be followed by either attribute specifications, ">" or "/>".
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:264)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:292)
Do you call doFinal() with the final chunk of data?
public void decrypt(InputStream in, OutputStream out) {
try
{
paddedBufferedBlockCipher.init(false,
new ParametersWithIV(keyParam, _defaultIv));
byte[] buffer = new byte[4096];
byte[] outBuffer = new byte[4096];
for (int count = 0; (count = in.read(buffer)) != -1;) {
int c2 = paddedBufferedBlockCipher.processBytes(buffer, 0,
count, outBuffer, 0);
out.write(outBuffer, 0, c2);
}
count = paddedBufferedBlockCipher.doFinal(outBuffer, 0);
out.write(outBuffer, 0, count);
}
catch(Exception e) {
e.printStackTrace();
}
}
I'm writing an application that signs and envelopes data using BouncyCastle.
I need to sign large files so instead of using the CMSSignedDataGenerator (which works just fine for small files) I chose to use CMSSignedDataStreamGenerator. The signed files are being generated but the SHA1 hash does not match with the original file. Could you help me?
Here`s the code:
try {
int buff = 16384;
byte[] buffer = new byte[buff];
int unitsize = 0;
long read = 0;
long offset = file.length();
FileInputStream is = new FileInputStream(file);
FileOutputStream bOut = new FileOutputStream("teste.p7s");
Certificate cert = keyStore.getCertificate(alias);
PrivateKey key = (PrivateKey) keyStore.getKey(alias, null);
Certificate[] chain = keyStore.getCertificateChain(alias);
CertStore certStore = CertStore.getInstance("Collection",new CollectionCertStoreParameters(Arrays.asList(chain)));
CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
gen.addSigner(key, (X509Certificate) cert, CMSSignedDataGenerator.DIGEST_SHA1, "SunPKCS11-iKey2032");
gen.addCertificatesAndCRLs(certStore);
OutputStream sigOut = gen.open(bOut,true);
while (read < offset) {
unitsize = (int) (((offset - read) >= buff) ? buff : (offset - read));
is.read(buffer, 0, unitsize);
sigOut.write(buffer);
read += unitsize;
}
sigOut.close();
bOut.close();
is.close();
I don't know what I'm doing wrong.
I agree with Rasmus Faber, the read/write loop is dodgy.
Replace this:
while (read < offset) {
unitsize = (int) (((offset - read) >= buff) ? buff : (offset - read));
is.read(buffer, 0, unitsize);
sigOut.write(buffer);
read += unitsize;
}
with:
org.bouncycastle.util.io.Streams.pipeAll(is, sigOut);
One possible problem is the line
is.read(buffer, 0, unitsize);
FileInputStream.read is only guaranteed to read between 1 and unitsize bytes.
Try writing
int actuallyRead = is.read(buffer, 0, unitsize);
sigOut.write(buffer, 0, actuallyRead);
read += actuallyRead;