mobile/android/base/sync/crypto/HKDF.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko.sync.crypto;
     7 import java.security.InvalidKeyException;
     8 import java.security.Key;
     9 import java.security.NoSuchAlgorithmException;
    11 import javax.crypto.Mac;
    12 import javax.crypto.spec.SecretKeySpec;
    14 import org.mozilla.gecko.sync.Utils;
    16 /*
    17  * A standards-compliant implementation of RFC 5869
    18  * for HMAC-based Key Derivation Function.
    19  * HMAC uses HMAC SHA256 standard.
    20  */
    21 public class HKDF {
    22   public static String HMAC_ALGORITHM = "hmacSHA256";
    24   /**
    25    * Used for conversion in cases in which you *know* the encoding exists.
    26    */
    27   public static final byte[] bytes(String in) {
    28     try {
    29       return in.getBytes("UTF-8");
    30     } catch (java.io.UnsupportedEncodingException e) {
    31       return null;
    32     }
    33   }
    35   public static final int BLOCKSIZE     = 256 / 8;
    36   public static final byte[] HMAC_INPUT = bytes("Sync-AES_256_CBC-HMAC256");
    38   /*
    39    * Step 1 of RFC 5869
    40    * Get sha256HMAC Bytes
    41    * Input: salt (message), IKM (input keyring material)
    42    * Output: PRK (pseudorandom key)
    43    */
    44   public static byte[] hkdfExtract(byte[] salt, byte[] IKM) throws NoSuchAlgorithmException, InvalidKeyException {
    45     return digestBytes(IKM, makeHMACHasher(salt));
    46   }
    48   /*
    49    * Step 2 of RFC 5869.
    50    * Input: PRK from step 1, info, length.
    51    * Output: OKM (output keyring material).
    52    */
    53   public static byte[] hkdfExpand(byte[] prk, byte[] info, int len) throws NoSuchAlgorithmException, InvalidKeyException {
    54     Mac hmacHasher = makeHMACHasher(prk);
    56     byte[] T  = {};
    57     byte[] Tn = {};
    59     int iterations = (int) Math.ceil(((double)len) / ((double)BLOCKSIZE));
    60     for (int i = 0; i < iterations; i++) {
    61       Tn = digestBytes(Utils.concatAll(Tn, info, Utils.hex2Byte(Integer.toHexString(i + 1))),
    62                        hmacHasher);
    63       T = Utils.concatAll(T, Tn);
    64     }
    66     byte[] result = new byte[len];
    67     System.arraycopy(T, 0, result, 0, len);
    68     return result;
    69   }
    71   /*
    72    * Make HMAC key
    73    * Input: key (salt)
    74    * Output: Key HMAC-Key
    75    */
    76   public static Key makeHMACKey(byte[] key) {
    77     if (key.length == 0) {
    78       key = new byte[BLOCKSIZE];
    79     }
    80     return new SecretKeySpec(key, HMAC_ALGORITHM);
    81   }
    83   /*
    84    * Make an HMAC hasher
    85    * Input: Key hmacKey
    86    * Ouput: An HMAC Hasher
    87    */
    88   public static Mac makeHMACHasher(byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
    89     Mac hmacHasher = null;
    90     hmacHasher = Mac.getInstance(HMAC_ALGORITHM);
    92     // If Mac.getInstance doesn't throw NoSuchAlgorithmException, hmacHasher is
    93     // non-null.
    94     assert(hmacHasher != null);
    96     hmacHasher.init(makeHMACKey(key));
    97     return hmacHasher;
    98   }
   100   /*
   101    * Hash bytes with given hasher
   102    * Input: message to hash, HMAC hasher
   103    * Output: hashed byte[].
   104    */
   105   public static byte[] digestBytes(byte[] message, Mac hasher) {
   106     hasher.update(message);
   107     byte[] ret = hasher.doFinal();
   108     hasher.reset();
   109     return ret;
   110   }
   112   public static byte[] derive(byte[] skm, byte[] xts, byte[] ctxInfo, int dkLen) throws InvalidKeyException, NoSuchAlgorithmException {
   113     return hkdfExpand(hkdfExtract(xts, skm), ctxInfo, dkLen);
   114   }
   116   public static void deriveMany(byte[] skm, byte[] xts, byte[] ctxInfo, byte[]... keys) throws InvalidKeyException, NoSuchAlgorithmException {
   117     int length = 0;
   118     for (byte[] key : keys) {
   119       length += key.length;
   120     }
   121     byte[] derived = hkdfExpand(hkdfExtract(xts, skm), ctxInfo, length);
   122     int offset = 0;
   123     for (byte[] key : keys) {
   124       System.arraycopy(derived, offset, key, 0, key.length);
   125       offset += key.length;
   126     }
   127   }
   128 }

mercurial