Want more features on Pastebin? Sign Up, it's FREE!
Guest

Rfc2898DeriveBytes

By: Chiddix on Jul 17th, 2012  |  syntax: Java  |  size: 4.87 KB  |  views: 301  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. import java.io.UnsupportedEncodingException;
  2. import java.security.InvalidKeyException;
  3. import java.security.NoSuchAlgorithmException;
  4.  
  5. import javax.crypto.Mac;
  6. import javax.crypto.spec.SecretKeySpec;
  7.  
  8. /**
  9.  * RFC 2898 password derivation compatible with .NET Rfc2898DeriveBytes class.
  10.  */
  11. public class Rfc2898DeriveBytes {
  12.  
  13.         private Mac _hmacSha1;
  14.         private byte[] _salt;
  15.         private int _iterationCount;
  16.  
  17.         private byte[] _buffer = new byte[20];
  18.         private int _bufferStartIndex = 0;
  19.         private int _bufferEndIndex = 0;
  20.         private int _block = 1;
  21.  
  22.         /**
  23.          * Creates new instance.
  24.          *
  25.          * @param password
  26.          *            The password used to derive the key.
  27.          * @param salt
  28.          *            The key salt used to derive the key.
  29.          * @param iterations
  30.          *            The number of iterations for the operation.
  31.          * @throws NoSuchAlgorithmException
  32.          *             HmacSHA1 algorithm cannot be found.
  33.          * @throws InvalidKeyException
  34.          *             Salt must be 8 bytes or more. -or- Password cannot be null.
  35.          */
  36.         public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations) throws NoSuchAlgorithmException, InvalidKeyException {
  37.                 if ((salt == null) || (salt.length < 8)) {
  38.                         throw new InvalidKeyException("Salt must be 8 bytes or more.");
  39.                 }
  40.                 if (password == null) {
  41.                         throw new InvalidKeyException("Password cannot be null.");
  42.                 }
  43.                 this._salt = salt;
  44.                 this._iterationCount = iterations;
  45.                 this._hmacSha1 = Mac.getInstance("HmacSHA1");
  46.                 this._hmacSha1.init(new SecretKeySpec(password, "HmacSHA1"));
  47.         }
  48.  
  49.         /**
  50.          * Creates new instance.
  51.          *
  52.          * @param password
  53.          *            The password used to derive the key.
  54.          * @param salt
  55.          *            The key salt used to derive the key.
  56.          * @param iterations
  57.          *            The number of iterations for the operation.
  58.          * @throws NoSuchAlgorithmException
  59.          *             HmacSHA1 algorithm cannot be found.
  60.          * @throws InvalidKeyException
  61.          *             Salt must be 8 bytes or more. -or- Password cannot be null.
  62.          * @throws UnsupportedEncodingException
  63.          *             UTF-8 encoding is not supported.
  64.          */
  65.         public Rfc2898DeriveBytes(String password, byte[] salt, int iterations) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
  66.                 this(password.getBytes("UTF8"), salt, iterations);
  67.         }
  68.  
  69.         /**
  70.          * Creates new instance.
  71.          *
  72.          * @param password
  73.          *            The password used to derive the key.
  74.          * @param salt
  75.          *            The key salt used to derive the key.
  76.          * @throws NoSuchAlgorithmException
  77.          *             HmacSHA1 algorithm cannot be found.
  78.          * @throws InvalidKeyException
  79.          *             Salt must be 8 bytes or more. -or- Password cannot be null.
  80.          * @throws UnsupportedEncodingException
  81.          *             UTF-8 encoding is not supported.
  82.          */
  83.         public Rfc2898DeriveBytes(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
  84.                 this(password, salt, 0x3e8);
  85.         }
  86.  
  87.         /**
  88.          * Returns a pseudo-random key from a password, salt and iteration count.
  89.          *
  90.          * @param count
  91.          *            Number of bytes to return.
  92.          * @return Byte array.
  93.          */
  94.         public byte[] getBytes(int count) {
  95.                 byte[] result = new byte[count];
  96.                 int resultOffset = 0;
  97.                 int bufferCount = this._bufferEndIndex - this._bufferStartIndex;
  98.  
  99.                 if (bufferCount > 0) { // if there is some data in buffer
  100.                         if (count < bufferCount) { // if there is enough data in buffer
  101.                                 System.arraycopy(this._buffer, this._bufferStartIndex, result, 0, count);
  102.                                 this._bufferStartIndex += count;
  103.                                 return result;
  104.                         }
  105.                         System.arraycopy(this._buffer, this._bufferStartIndex, result, 0, bufferCount);
  106.                         this._bufferStartIndex = this._bufferEndIndex = 0;
  107.                         resultOffset += bufferCount;
  108.                 }
  109.  
  110.                 while (resultOffset < count) {
  111.                         int needCount = count - resultOffset;
  112.                         this._buffer = this.func();
  113.                         if (needCount > 20) { // we one (or more) additional passes
  114.                                 System.arraycopy(this._buffer, 0, result, resultOffset, 20);
  115.                                 resultOffset += 20;
  116.                         } else {
  117.                                 System.arraycopy(this._buffer, 0, result, resultOffset, needCount);
  118.                                 this._bufferStartIndex = needCount;
  119.                                 this._bufferEndIndex = 20;
  120.                                 return result;
  121.                         }
  122.                 }
  123.                 return result;
  124.         }
  125.  
  126.         private byte[] func() {
  127.                 this._hmacSha1.update(this._salt, 0, this._salt.length);
  128.                 byte[] tempHash = this._hmacSha1.doFinal(getBytesFromInt(this._block));
  129.  
  130.                 this._hmacSha1.reset();
  131.                 byte[] finalHash = tempHash;
  132.                 for (int i = 2; i <= this._iterationCount; i++) {
  133.                         tempHash = this._hmacSha1.doFinal(tempHash);
  134.                         for (int j = 0; j < 20; j++) {
  135.                                 finalHash[j] = (byte) (finalHash[j] ^ tempHash[j]);
  136.                         }
  137.                 }
  138.                 if (this._block == 2147483647) {
  139.                         this._block = -2147483648;
  140.                 } else {
  141.                         this._block += 1;
  142.                 }
  143.  
  144.                 return finalHash;
  145.         }
  146.  
  147.         private static byte[] getBytesFromInt(int i) {
  148.                 return new byte[] { (byte) (i >>> 24), (byte) (i >>> 16), (byte) (i >>> 8), (byte) i };
  149.         }
  150.  
  151. }
clone this paste RAW Paste Data