diff options
Diffstat (limited to 'src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java')
-rw-r--r-- | src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java | 107 |
1 files changed, 30 insertions, 77 deletions
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java index 876bd93..1e3b196 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java +++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java @@ -1,17 +1,17 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +/* Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.google.security.cryptauth.lib.securemessage; import com.google.security.annotations.SuppressInsecureCipherModeCheckerReviewed; @@ -132,6 +132,7 @@ public class CryptoOps { * A salt value specific to this library, generated as SHA-256("SecureMessage") */ private static final byte[] SALT = sha256("SecureMessage"); + private static final byte[] CONSTANT_01 = { 0x01 }; // For convenience /** * Signs {@code data} using the algorithm specified by {@code sigType} with {@code signingKey}. @@ -411,31 +412,10 @@ public class CryptoOps { */ public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info) throws NoSuchAlgorithmException, InvalidKeyException { - return hkdf(inputKeyMaterial, salt, info, /* length= */ 32); - } - - /** - * Implements HKDF (RFC 5869) with the SHA-256 hash. - * - * <p>Please make sure to select a salt that is fixed and unique for your codebase, and use the - * {@code info} parameter to specify any additional bits that should influence the derived key. - * - * @param inputKeyMaterial master key from which to derive sub-keys - * @param salt a (public) randomly generated 256-bit input that can be re-used - * @param info arbitrary information that is bound to the derived key (i.e., used in its creation) - * @param length length of returned key material - * @return raw derived key bytes = HKDF-SHA256(inputKeyMaterial, salt, info) - * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed - */ - public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info, int length) - throws NoSuchAlgorithmException, InvalidKeyException { if ((inputKeyMaterial == null) || (salt == null) || (info == null)) { throw new NullPointerException(); } - if (length < 0) { - throw new IllegalArgumentException("Length must be positive"); - } - return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info, length); + return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info); } /** @@ -484,12 +464,12 @@ public class CryptoOps { } /** - * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is used - * to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable for use - * with HKDF expansion function (which produces the actual derived key). + * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is + * used to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable + * for use with HKDF expansion function (which produces the actual derived key). * - * @see #hkdfSha256Expand(byte[], byte[], int) - * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC) + * @see #hkdfSha256Expand(byte[], byte[]) + * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC) * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable */ @@ -511,15 +491,15 @@ public class CryptoOps { } /** - * HKDF (RFC 5869) expansion function, using the SHA-256 hash function. + * Special case of HKDF (RFC 5869) expansion function, using the SHA-256 hash function and + * allowing for a maximum output length of 256 bits. * - * @param pseudoRandomKey should be generated by {@link #hkdfSha256Extract(SecretKey, byte[])} + * @param pseudoRandomKey should be generated by {@link #hkdfSha256Expand(byte[], byte[])} * @param info arbitrary information the derived key should be bound to - * @param length length of the output key material in bytes * @return raw derived key bytes = HMAC-SHA256(pseudoRandomKey, info | 0x01) * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable */ - private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info, int length) + private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info) throws NoSuchAlgorithmException { Mac macScheme = Mac.getInstance("HmacSHA256"); try { @@ -527,38 +507,11 @@ public class CryptoOps { } catch (InvalidKeyException e) { throw new AssertionError(e); // This should never happen } - - // Number of blocks N = ceil(hash length / output length). - int blocks = length / 32; - if (length % 32 > 0) { - blocks += 1; - } - - // The counter used to generate the blocks according to the RFC is only one byte long, - // which puts a limit on the number of blocks possible. - if (blocks > 0xFF) { - throw new IllegalArgumentException("Maximum HKDF output length exceeded."); - } - - byte[] outputBlock = new byte[32]; - byte[] counter = new byte[1]; - byte[] output = new byte[32 * blocks]; - for (int i = 0; i < blocks; ++i) { - macScheme.reset(); - if (i > 0) { - // Previous block - macScheme.update(outputBlock); - } - // Arbitrary info - macScheme.update(info); - // Counter - counter[0] = (byte) (i + 1); - outputBlock = macScheme.doFinal(counter); - - System.arraycopy(outputBlock, 0, output, 32 * i, 32); - } - - return subarray(output, 0, length); + // Arbitrary "info" to be included in the MAC. + macScheme.update(info); + // Note that RFC 5869 computes number of blocks N = ceil(hash length / output length), but + // here we only deal with a 256 bit hash up to a 256 bit output, yielding N=1. + return macScheme.doFinal(CONSTANT_01); } } |