• No results found

CRYPTO-ALGORITHMS IN JAVA

In document Versatile Java - Deepak Mali 351 (Page 164-185)

Getting Strarted

Here we will study the Java cryptography architecture for secure hashing , files hashing and password hashing. This can be utilized in java android applications and desktop applications. The various types of hashing described are simple hashing , Stream based hashing ,Message Authentication Code

And Secure Password hashing using

PBKDF2/PKCS#5.(following the security scheme PBKDF2 from the security standard PKCS#5)

Crypto Algorithms

Java 1.8 includes all state of the art crypto algorithms .We used apache codec which includes hash encoding base 64 which

import java.util.logging.Level;

import java.util.logging.Logger;

/**

*

* @author deepakmali */

public class SimpleHash { /**

* @param args the command line arguments */

public static void main(String[] args) { // TODO code application logic here String str = "Test String";

try {

MessageDigest md =MessageDigest.getInstance("MD5");

byte [] hash = md.digest(str.getBytes("UTF-8"));

System.out.println(hash.length);

for (byte b : hash)

System.out.print(b + " ,");

} catch (NoSuchAlgorithmException ex) {

Logger.getLogger(SimpleHash.class.getName()).log(Level.SE VERE, null, ex);

} catch (UnsupportedEncodingException ex) {

Input and output both are in bytes format for the hash function and commons codec will display the result of the hash function .Digest method produces a direct output.The method getByptes() is very error prone since it depends on the default encoding of the JVM running.Its good to mention the encoding we want to use with getBytes() method- in our case its UTF -8 . The console output is a MD5 hash of the length of 16 - -67 ,8 ,-70 ,60 ,-104 ,46 ,-86 ,-41 ,104 ,96 ,37 ,54 ,-5 ,-114 ,17 ,-124 Lets now write a code to verify the MD5 checksum for the apache-codec file downloaded from apache website .We will create the hash value for the file .We will create the helper method to read the bytes from the file .It will read a file or any other input stream and return a byte array. Following is the

import java.security.NoSuchAlgorithmException;

import java.util.logging.Level;

import java.util.logging.Logger;

import org.apache.commons.codec.binary.Hex;

/**

*

* @author deepakmali */

public class FileHash {

public static void main(String[] args) throws IOException { // TODO code application logic here

String path =

"C:\\Users\\deepakmali\\Desktop\\Aadhar\\commons-codec-1.10-bin.zip";

byte [] bytes = Helper.read(new FileInputStream(path));

try {

MessageDigest md =MessageDigest.getInstance("MD5");

byte [] hash = md.digest(bytes);

System.out.println(hash.length);

for (byte b : hash)

System.out.print(b + " ,");

String hash_encoded = Hex.encodeHexString(hash);

System.out.println (hash_encoded);

} catch (NoSuchAlgorithmException ex) {

Logger.getLogger(SimpleHash.class.getName()).log(Level.SE VERE, null, ex);

} } }

package javacryptography;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

/**

*

* @author deepakmali */

public class Helper {

public static byte [] read (InputStream is) throws IOException{

ByteArrayOutputStream bos =new ByteArrayOutputStream();

byte [] buffer = new byte [1024 * 16];

int length ; while (true) {

length= is.read(buffer);

if (length <0) break;

bos.write(buffer,0,length);

}

is.close();

return bos.toByteArray();

} }

File Stream Hash and MAC

We want to work stream based in case the file is huge .We will now work on the file stream hash We make use of an Index based method to update the digest . In cryptography , authentication codes are abbreviated as MAC .We should not confuse them with the Ethernet address .Mac can also be realized using hash functions as a basis. In SSL ,a HMAC is used to build a MAC and is used to hash a secret document . Secret can be arbitrary byte vector or password based .We need to adhere a secret to the hash using an init method .We will still get a 16 bytes output but its now a password based hash (a MAC)We can use other hash functions and also once the

password is change the result is going to change .For MAC , we can use the SHA256 algorithm .Crypto-specialists have created the algorithm which is very mature and easy to use .The following are the snippet for File Stream Hash and MAC.

import java.io.FileInputStream;

import java.io.IOException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.logging.Level;

import java.util.logging.Logger;

import org.apache.commons.codec.binary.Hex;

/**

*

* @author deepakmali */

public class FileStreamHash {

public static void main(String[] args) throws IOException { // TODO code application logic here

String path =

"C:\\Users\\deepakmali\\Desktop\\Aadhar\\commons-codec-1.10-bin.zip";

try {

MessageDigest md =MessageDigest.getInstance("MD5");

byte [] buffer = new byte [1024 * 16];

int length ;

FileInputStream fis = new FileInputStream(path);

while (true) {

length= fis.read(buffer);

if (length <0) break;

md.update(buffer,0,length);

}

fis.close();

byte[] hash = md.digest();

for (byte b : hash)

System.out.print(b + " ,");

System.out.println(hash.length);

String hash_encoded = Hex.encodeHexString(hash);

System.out.println (hash_encoded);

} catch (NoSuchAlgorithmException ex) {

Logger.getLogger(SimpleHash.class.getName()).log(Level.SE VERE, null, ex);

} } }

package javacryptography;

import java.io.UnsupportedEncodingException;

import java.security.InvalidKeyException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.logging.Level;

import java.util.logging.Logger;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;

/**

*

* @author deepakmali */

public class SimpleMac {

public static void main(String[] args) { String str = "Test String";

try {

// Mac mac = Mac.getInstance("HMACMD5");

Mac mac = Mac.getInstance("HMACSHA256");

mac.init(new SecretKeySpec("Password ".getBytes("UTF-8"),""));

byte [] hash = mac.doFinal(str.getBytes("UTF-8"));

System.out.println(hash.length);

for (byte b : hash)

System.out.print(b + " ,");

String hash_encoded = Hex.encodeHexString(hash);

System.out.println (hash_encoded);

} catch (NoSuchAlgorithmException ex) {

Logger.getLogger(SimpleHash.class.getName()).log(Level.SE VERE, null, ex);

} catch (UnsupportedEncodingException ex) {

Logger.getLogger(SimpleHash.class.getName()).log(Level.SE VERE, null, ex);

} catch (InvalidKeyException ex) {

Logger.getLogger(SimpleMac.class.getName()).log(Level.SEV ERE, null, ex);

} } }

PBKDF2

The problem with these hash functions is the lengths of the password is short and brute force attacks are possible. Crypto specialist created special hashing schemes for password hashing. Secure password hashing include salting (Addition of data to the password before the hash is generated) and iterations (re-hashing multiple times).Secure schemes for hashing the password is PBKDF2 from PKCS5.A very popular implementation of PBKDF2 is done by the open source crypto provider Bouncy Castle. It is so robust that even if the attacker gets the hash , he will not be able to restore the password .An

* and allows to play around with the input parameters (***) * for better understanding.

*

* For production usage, please note the "TODO" tags!

*

* Works for Java and Android.

* */

public class PBKDF2Example {

public static void main(String[] args) throws Exception{

String demo_password = "Password";

//TODO: Has to be

//1)generated by secure random //2) individual per case

//3) with appropriate length byte[] demo_salt = {

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, //1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1 6, //***

};

int demo_iterationcount = 10000;

//demo_iterationcount++; //***

int demo_size = 256; //size in bits

//demo_size+=8; //***

//TODO: Salt + Iteration count + Size have to be stored with the hash to recalculate the hash later

// -> Iteration count + Size can be constant values, the salt has to be stored individually

//--- //---CREATION--- //---

PBKDF2 hashgen = new PBKDF2();

hashgen.init(demo_password.getBytes ("UTF8"), demo_salt, demo_iterationcount, demo_size);

byte[] rawhash =

hashgen.generateDerivedParameters();

System.out.println("LEN: " + rawhash.length * 8);

for(byte b: rawhash)

hashgen = new PBKDF2();

hashgen.init(demo_password.getBytes ("UTF8"), demo_salt, demo_iterationcount, demo_size);

rawhash = hashgen.generateDerivedParameters();

System.out.println("LEN: " + rawhash.length * 8);

for(byte b: rawhash) System.out.print(b + ", ");

System.out.println("\nVerification: "

+ Arrays.equals(stored_hash, rawhash));

} }

package pbkdf2_test;

/**

*

* @author deepakmali */

/**

* This class is based on the Bouncy Castle Java class *

org.bouncycastle.crypto.generators.PKCS5S2ParametersGenera tor

*

* It uses the SHA512 HMAC as default. Only JCE/JCA classes are being used.

* HmacSHA512 is included in JRE 1.8++. This class also runs below 1.8.

* Then, BC or others have to be used to include the HmacSHA512 algorithm

* or a different HMAC has to be used.

* * *

* The Bouncy Castle License *

* Copyright (c) 2000-2015 The Legion Of The Bouncy Castle Inc.

* (http://www.bouncycastle.org) * <p>

* Permission is hereby granted, free of charge, to any person obtaining a copy

* of this software and associated documentation files (the

"Software"), to deal

* in the Software without restriction, including without limitation the rights

* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

* copies of the Software, and to permit persons to whom the Software is

* furnished to do so, subject to the following conditions:

* <p>

* The above copyright notice and this permission notice shall be included in

* all copies or substantial portions of the Software.

* <p>

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

* SOFTWARE.

* *

*

* Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.

* <p>

* The document this implementation is based on can be found at <a

* href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html> RSA's PKCS5

* Page</a>

*/

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

public class PBKDF2 {

private byte[] password;

private byte[] salt;

private int iterationCount;

private int keysize;

private Mac hMac;

private byte[] state;

public PBKDF2() { try {

hMac = Mac.getInstance("HmacSHA512");

} catch (Exception e) { e.printStackTrace();

}

state = new

byte[hMac.getMacLength()];

}

private void F(byte[] S, int c, byte[]

iBuf, byte[] out, int outOff) throws Exception{

if (c <= 0) {

throw new

IllegalArgumentException("iteration count must be at least 1.");

}

if (S != null) {

hMac.update(S, 0, S.length);

}

hMac.update(iBuf, 0, iBuf.length);

hMac.doFinal(state, 0);

System.arraycopy(state, 0, out, outOff, state.length);

for (int count = 1; count < c; count++) {

hMac.update(state, 0, state.length);

hMac.doFinal(state, 0);

for (int j = 0; j != state.length; j++) { out[outOff + j] ^= state[j];

} }

}

private byte[] generateDerivedKey(int dkLen) throws Exception{

int hLen = hMac.getMacLength();

int l = (dkLen + hLen - 1) / hLen;

byte[] iBuf = new byte[4];

byte[] outBytes = new byte[l * hLen];

int outPos = 0;

hMac.init(new SecretKeySpec(password, ""));

for (int i = 1; i <= l; i++) { // Increment the value in 'iBuf'

int pos = 3;

while (++iBuf[pos] == 0) { --pos;

} F(salt, iterationCount, iBuf, outBytes, outPos);

outPos += hLen;

}

return outBytes;

}

public void init(byte[] password, byte[] salt, int iterationCount, int keysize) {

keysize = keysize / 8;

this.password = password;

this.salt = salt;

this.iterationCount = iterationCount;

this.keysize = keysize;

}

public byte[] generateDerivedParameters() throws Exception {

byte[] dKey =

generateDerivedKey(keysize);

if(dKey.length < keysize) throw new IllegalStateException("General failure: Generated array not in keysize!");

if (dKey.length > keysize){

byte[] dk2 = new byte[keysize];

System.arraycopy(dKey, 0, dk2, 0, keysize);

dKey = dk2;

} return dKey;

} }

In document Versatile Java - Deepak Mali 351 (Page 164-185)

Related documents