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.

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

mercurial