1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.subtle; 18 19 import java.security.GeneralSecurityException; 20 import javax.crypto.Mac; 21 import javax.crypto.spec.SecretKeySpec; 22 23 /** 24 * This class implements HMAC-based Extract-and-Expand Key Derivation Function (HKDF), as described 25 * in <a href="https://tools.ietf.org/html/rfc5869">RFC 5869</a>. 26 * 27 * @since 1.0.0 28 */ 29 public final class Hkdf { 30 31 /** 32 * Computes an HKDF. 33 * 34 * @param macAlgorithm the MAC algorithm used for computing the Hkdf. I.e., "HMACSHA1" or 35 * "HMACSHA256". 36 * @param ikm the input keying material. 37 * @param salt optional salt. A possibly non-secret random value. If no salt is provided (i.e. if 38 * salt has length 0) then an array of 0s of the same size as the hash digest is used as salt. 39 * @param info optional context and application specific information. 40 * @param size The length of the generated pseudorandom string in bytes. The maximal size is 41 * 255.DigestSize, where DigestSize is the size of the underlying HMAC. 42 * @return size pseudorandom bytes. 43 * @throws GeneralSecurityException if the {@code macAlgorithm} is not supported or if {@code 44 * size} is too large or if {@code salt} is not a valid key for macAlgorithm (which should not 45 * happen since HMAC allows key sizes up to 2^64). 46 */ computeHkdf( String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size)47 public static byte[] computeHkdf( 48 String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) 49 throws GeneralSecurityException { 50 Mac mac = EngineFactory.MAC.getInstance(macAlgorithm); 51 if (size > 255 * mac.getMacLength()) { 52 throw new GeneralSecurityException("size too large"); 53 } 54 if (salt == null || salt.length == 0) { 55 // According to RFC 5869, Section 2.2 the salt is optional. If no salt is provided 56 // then HKDF uses a salt that is an array of zeros of the same length as the hash digest. 57 mac.init(new SecretKeySpec(new byte[mac.getMacLength()], macAlgorithm)); 58 } else { 59 mac.init(new SecretKeySpec(salt, macAlgorithm)); 60 } 61 byte[] prk = mac.doFinal(ikm); 62 byte[] result = new byte[size]; 63 int ctr = 1; 64 int pos = 0; 65 mac.init(new SecretKeySpec(prk, macAlgorithm)); 66 byte[] digest = new byte[0]; 67 while (true) { 68 mac.update(digest); 69 mac.update(info); 70 mac.update((byte) ctr); 71 digest = mac.doFinal(); 72 if (pos + digest.length < size) { 73 System.arraycopy(digest, 0, result, pos, digest.length); 74 pos += digest.length; 75 ctr++; 76 } else { 77 System.arraycopy(digest, 0, result, pos, size - pos); 78 break; 79 } 80 } 81 return result; 82 } 83 84 /** 85 * Computes symmetric key for ECIES with HKDF from the provided parameters. 86 * 87 * @param ephemeralPublicKeyBytes the encoded ephemeral public key, i.e. the KEM part of the 88 * hybrid encryption. In some versions of ECIES (e.g. IEEE P1363a) this argument is optional. 89 * Shoup strongly prefers the inclusion of this argument in 90 * http://eprint.iacr.org/2001/112.pdf (see discussion of the value C0 in Section 15.6, and 91 * 15.6.1) 92 * @param sharedSecret the shared DH secret. This typically is the x-coordinate of the secret 93 * point. 94 * @param hmacAlgo the HMAC used (e.g. "HmacSha256") 95 * @param hkdfInfo TODO(bleichen): determine what are good values for Info and salt and what are 96 * not good values. The ISO standard proposal http://eprint.iacr.org/2001/112.pdf does not 97 * allow additional values for the key derivation (see Section 15.6.2) 98 * @param hkdfSalt 99 * @param keySizeInBytes the size of the key material for the DEM key. 100 * @throws GeneralSecurityException if hmacAlgo is not supported 101 */ computeEciesHkdfSymmetricKey( final byte[] ephemeralPublicKeyBytes, final byte[] sharedSecret, String hmacAlgo, final byte[] hkdfSalt, final byte[] hkdfInfo, int keySizeInBytes)102 public static byte[] computeEciesHkdfSymmetricKey( 103 final byte[] ephemeralPublicKeyBytes, 104 final byte[] sharedSecret, 105 String hmacAlgo, 106 final byte[] hkdfSalt, 107 final byte[] hkdfInfo, 108 int keySizeInBytes) 109 throws GeneralSecurityException { 110 byte[] hkdfInput = Bytes.concat(ephemeralPublicKeyBytes, sharedSecret); 111 return Hkdf.computeHkdf(hmacAlgo, hkdfInput, hkdfSalt, hkdfInfo, keySizeInBytes); 112 } 113 Hkdf()114 private Hkdf() {} 115 } 116