I am trying to figure out how to read multiple digests (md5, sha1, gpg) based on the same InputStream using DigestInputStream. From what I've checked in the documentation, it seems to be possible by cloning the digest. Could somebody please illustrate this?
I don't want to be re-reading the stream in order to calculate the checksums.
You could wrap a DigestInputStream around a DigestInputStream and so on recursively:
DigestInputStream shaStream = new DigestInputStream(
inStream, MessageDigest.getInstance("SHA-1"));
DigestInputStream md5Stream = new DigestInputStream(
shaStream, MessageDigest.getInstance("MD5"));
// VERY IMPORTANT: read from final stream since it's FilterInputStream
byte[] shaDigest = shaStream.getMessageDigest().digest();
byte[] md5Digest = md5Stream.getMessageDigest().digest();
The Javadoc is pretty clear. You can use clone only to calculate different intermediate digests using the same algorithm. You cannot use DigestInputStream to calculate different digest algorithms without reading the stream multiple times. You must use a regular InputStream and multiple MessageDigest objects; read the data once, passing each buffer to all MessageDigest objects to get multiple digests with different algorithms.
You could easily encapsulate this in your own variant of DigestInputStream, say MultipleDigestInputStream that follows the same general approach but accepts a collection of MessageDigest objects or algorithm names.
Pseudojava (error handling omitted)
MessageDigest sha = MessageDigest.getInstance("SHA-1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
InputStream input = ...;
byte[] buffer = new byte[BUFFER_SIZE];
int len;
while((len = input.read(buffer)) >= 0)
{
sha.update(buffer,0,len);
md5.update(buffer,0,len);
...
}
byte[] shaDigest = sha.digest();
byte[] md5Digest = md5.digest();
Related
I am trying to load some library ".so" / ".dll" files using below code
System.load("some file");
then after performing Static application security testing (SAST) using checkmarx tool
it is complaining Download of Code Without Integrity Check issue.
then I tried to fix the Download of Code Without Integrity Check SAST issue using checksum
I generated a library file checksum using a sha-512 algorithm and kept it in a String constant
public static final String TRUSTED_SHA512 = "12af30d9ffc1cdd85d21e73c8c81b7c379a9b4ab2ea5676cd9d232788e2b44fbab876796104f37d0f6a5f7bc5f97eb3663e432785b94039b5320bbfac3d19516";
now before loading the file, I am computing hash again with the same algorithm and checking it against String constant TRUSTED_SHA512
MessageDigest md = MessageDigest.getInstance("SHA-512");
String sha512ofQrcToolsWrapper = ChecksumHelper.getFileChecksum(md,temp);
if(sha512ofQrcToolsWrapper.equalsIgnoreCase(ServiceConstants.TRUSTED_SHA512_OF_QRCTOOLSWRAPPER)) {
System.load(temp.getAbsolutePath());
}else{
throw new Exception("failed to load windows dll file : Checksum mismatched");
}
Now checkmarx tool is giving one more issue Use of a one-way hash without a salt
then i updated message digest with static salt value. The
reason behind using fix salt value instead of random value is that we want to compute same hash at runtime to check with the one already there in constant
public static String getFileChecksum(MessageDigest digest, File file) throws IOException, NoSuchAlgorithmException {
//Get file input stream for reading the file content
FileInputStream fis = new FileInputStream(file);
//Create byte array to read data in chunks
byte[] byteArray = new byte[1024];
int bytesCount = 0;
//Read file data and update in message digest
while ((bytesCount = fis.read(byteArray)) != -1) {
digest.update(byteArray, 0, bytesCount);
}
//Static salt value
digest.update(getSalt());
//close the stream; We don't need it now.
fis.close();
//Get the hash's bytes
byte[] bytes = digest.digest();
//This bytes[] has bytes in decimal format;
//Convert it to hexadecimal format
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
//return complete hash
return sb.toString();
}
NOTE "getSalt() method is returning byte array with fixed values"
Still, checkmarx SAST is complaining both the issues
Download of code without Integrity check
Use of a one-way hash without a salt
please provide solution to fix these issues. let me know if anything else needed to clarify.
Thanks in advance
I understand md5 is mostly used for file checksum and we can use following code in java to generate md5 digest.
MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = Files.newInputStream(Paths.get("file.txt"))) {
DigestInputStream dis = new DigestInputStream(is, md);
/* Read stream to EOF as normal... */
}
byte[] digest = md.digest();
But I'd like to know what exactly is the input of the md function? the meta data of file or the text in file?
The input is the text in the file.
I'm developing an iPad app and using RNCryptor for the encryption and decryption on the device. There is a Java version of this encryption format available in the form of JNCryptor.
I now have data to be read from an InputStream, but I want to encrypt the data before it is read. I found a class called CipherInputStream, which seems to do exactly what I'm looking for. Only thing is, I need a Cipher (and Provider) to specify the encryption method, and I don't know how to do that. Is it even possible to define a custom Provider?
Does anyone have suggestions on alternative ways to use JNCryptor for the encryption of an InputStream?
In the end I ended up writing a class to read the InputStream, encrypt the data parts at a time, and write to a PipedOutputStream. This PipedOutputStream I then connected to a PipedInputStream, which I eventually returned. The encryption and writing to the PipedOutputStream happens on a separate thread to avoid deadlock.
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream(pin);
EncryptionPipe pipe = new EncryptionPipe(5, pout, in, cipher, mac, metaData);
//EncryptionPipe(int interval, OutputStream out, InputStream in
// ,Cipher cipher, Mac mac, byte[] metaData)
pipe.start();
return pin;
And in EncryptionPipe:
public class EncryptionPipe extends Thread {
...
#Override
public void run() {
try {
mac.update(metaData);
out.write(metaData);
byte[] buf = new byte[1024];
int bytesRead = 0;
byte[] crypted;
byte[] hmac;
while ((bytesRead = in.read(buf)) != -1) {
if (bytesRead < buf.length) {
//the doFinal methods add padding if necessary, important detail!
crypted = cipher.doFinal(buf, 0, bytesRead);
hmac = mac.doFinal(crypted);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(crypted);
bytes.write(hmac);
crypted = bytes.toByteArray();
bytesRead = crypted.length;
bytes.close();
} else {
crypted = cipher.update(buf, 0, bytesRead);
mac.update(crypted, 0, bytesRead);
}
out.write(crypted, 0, bytesRead);
synchronized (this) {
this.wait(interval);
}
}
out.close();
...
}
}
}
JNCryptor v1.1.0 was released yesterday and provides support for streaming encryption and decryption.
Use AES256JNCryptorInputStream to decrypt and AES256JNCryptorOutputStream to encrypt.
You can use the default Java provider. To instantiate a cipher you would use
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
This uses AES and Cipher Block Chaining mode. CBC only works on multiples of 16 bytes, so you're also specifying a way to pad your input to multiples of 16 bytes.
Here is some more sample AES code to get you started
I'm trying to encryt/decrypt using RSAEngine library at bouncy castle, with a 2048 bit length key. I'm able to create the keys, store in different files and get from the files, but when I decrypt an image it makes something that I don't know that the file decrypted is not shown correctly.Files are created correctly,and I think the problem is at processBlock method while encrypting and/or decrypting.The code is the following to encrypt:
InputStream clearTextFile;
FileOutputStream textFileProcessed=new FileOutputStream(fileName);
//getKey is a method I implemented and works correctly
RSAKeyParameters key=getKey(keyFileName);
RSAEngine rsaEngine=new RSAEngine();
rsaEngine.init(true,key);
clearTextFile=new FileInputStream(nameClearTextFile);
byte[] bytesReaded;
int nBytesReaded;
int inputBlockSize=rsaEngine.getInputBlockSize();
do
{
bytesReaded = new byte[inputBlockSize];
nBytesReaded=clearTextFile.read(bytesReaded);
if(nBytesReaded>-1)
{ //This is for the last block if it's not 256 byte length
if(nBytesReaded<inputBlockSize)
{
byte[] temp=new byte[nBytesReaded];
for(int i=0;i<nBytesReaded;i++)
{
temp[i]=bytesReaded[i];
}
byte[] encryptedText=rsaEngine.processBlock(temp,0,nBytesReaded);
textFileProcessed.write(encryptedText);
}
else
{
byte[] encryptedText=rsaEngine.processBlock(bytesReaded,0,inputBlockSize);
textFileProcessed.write(encryptedText);
}
}
}while(nBytesReaded>-1);
textFileProcessed.flush();
textFileProcessed.close();
textFileProcessed.close();
And to decrypt:
InputStream encryptedTextFile=new FileInputStream(nameOfFile);
OutputStream decryptedTextFile=new FileOutputStream(nameOfFile);
RSAKeyParameters key=getKey(nameKeyFile);
RSAEngine rsaEngine=new RSAEngine();
rsaEngine.init(false,key);
byte[] bytesReaded;
int nBytesReaded;
int inputBlockSize=rsaEngine.getInputBlockSize();
do
{
bytesLeidos = new byte[inputBlockSize];
nBytesReaded=encryptedTextFile.read(bytesReaded);
if(nBytesReaded>-1)
{
byte[] decryptedText=rsaEngine.processBlock(bytesReaded,0,inputBlockSize);
decryptedTextFile.write(decryptedText);
}
}while(nBytesReaded>-1);
decryptedTextFile.flush();
decryptedTextFile.close();
encryptedTextFile.close();
Thanks in advance
RSAEngine does not add padding, you will lose any leading zeros in your data blocks as a result. You need to use one of the encoding modes available as well.
I'd recommend using a symmetric key algorithm as well and just using RSA to encrypt the symmetric key. It will be a lot faster, and depending on your data, safer as well.
Regards,
David
I think you need to change this line:
if(nBytesReaded>1)
to this
if(nBytesReaded>-1)
And change this in the decypt part, maybe:
rsaEngine.init(false,clave);
to this
rsaEngine.init(false,key);
But there may be more. You aren't encrypting the whole input if the last block isn't full size.
I think i'm looking for some sort of basic file encryption but don't know where to start.
I'm looking for someone to tell me where to start looking or, even better, offer some code.
I've written a game that currently saves data to a general text file. This of course could be changed by anyone who wished to do so.
What i need is to create a file that can store integers and strings that is difficult if not impossible to be edited outside of the game.
In my searching i came across .dat files but they seemed more complicated that what i'm looking for.
All help is appreciated, Alex.
You can write your data to a ByteBuffer and then you can distort your data by a simple algorithm. For example, assume that the data you want to save is a String array, you can do this:
String[] data; // the data you want to save
int byteLength = 0;
byte[][] bytes = new byte[data.length][];
// Calculate the length of the content.
for(int i=0; i<data.length; i++) {
bytes[i] = data[i].getBytes();
byteLength += bytes[i].length;
byteLength += 4; // this is for an integer, which is for the length of the String
}
// Transfer the content to a ByteBuffer object
ByteBuffer buffer = ByteBuffer.allocate(byteLength);
for(int i=0; i<bytes.length; i++) {
// Put the length of the current byte array
buffer.putInt(bytes[i].length);
for(int j=0; j<bytes[i].length; j++) {
// Reverse the byte so that it can't be understood
buffer.put((byte)(~bytes[i][j]));
}
}
After writing all of your content to the ByteBuffer object, you can take the resulting byte array and write it down to a file.
FileOutputStream fos = new FileOutputStream("YourFileName.anyExtension");
fos.write(buffer.array());
fos.close();
While reading the file back, you should first read an integer, which is the length of the data you should read as byte array, then you should read this byte array.
FileInputStream fis = new FileInputStream("YourFileName.anyExtension");
DataInputStream dis = new DataInputStream(fis);
ArrayList<String> list = new ArrayList<String>();
byte[] bytes;
while(dis.available()) {
int length = dis.readInt();
bytes = new byte[length];
for(int i=0; i<length; i++) {
// Those bytes were reversed, right?
bytes[i] = (byte)(~dis.readByte());
}
// Convert byte array to String
String str = new String(bytes);
list.add(str);
}
Now you have an ArrayList of your String data.
Of course this is not the best, the safest, and the fastest algorithm. You can always find or create faster. But I think this is a good example of doing those kind of things.
If you are using Java you can just try and create a class that implements Serializable This way you can just create an object with all your meta info stored inside, serialize it, and when you wanna load it just deserialize it again.
Its not very safe though since you only need to know have the class it was made with, to deserialize it. But it is something to begin with.
Look into digital signatures, specifically HMACs. Those are pretty much exactly what you need, and the Java Crypto framework should make things fairly straightforward. Here's a potentially relevant SO entry: How to generate an HMAC in Java equivalent to a Python example?
You could pass your file writing stream thru a CipherOutputStream
Generate a random string, or number or anything. get its byte array, produce a key, and use it to encrypt your file.
byte password[] = (WHAT YOUR WANT. STRING, NUMBER, etc.).getBytes();
DESKeySpec desKeySpec;
try {
desKeySpec = new DESKeySpec(password);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(desKeySpec);
Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
desCipher.init(Cipher.ENCRYPT_MODE, key);
// Create stream
FileOutputStream fos = new FileOutputStream("Your file here");
BufferedOutputStream bos = new BufferedOutputStream(fos);
CipherOutputStream cos = new CipherOutputStream(bos, desCipher);
}
Now you can write to the file using cos
Reading the file is done the same way using the SecretKey object
SecretKey key = loadKey(); // Deserialize your SecretKey object
try {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
FileInputStream fis = new FileInputStream("Your file here");
BufferedInputStream bis = new BufferedInputStream(fis);
CipherInputStream cis = new CipherInputStream(bis, cipher);
now you can read using cis
The downside is you need to keep the SecretKey object (Serialize it or something) it wouldn't be a problem for any low level hacker to get the data (since the key is stored on the device) but it wouldn't allow just changing your data using a text editor.