1 // Copyright 2023 Google LLC 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.prf; 18 19 import com.google.crypto.tink.util.Bytes; 20 import com.google.errorprone.annotations.CanIgnoreReturnValue; 21 import com.google.errorprone.annotations.Immutable; 22 import java.security.GeneralSecurityException; 23 import java.security.InvalidAlgorithmParameterException; 24 import java.util.Objects; 25 import javax.annotation.Nullable; 26 27 /** Describes the parameters of an {@link HkdfPrfKey}. */ 28 public final class HkdfPrfParameters extends PrfParameters { 29 private static final int MIN_KEY_SIZE = 16; 30 31 /** The Hash algorithm used. */ 32 @Immutable 33 public static final class HashType { 34 public static final HashType SHA1 = new HashType("SHA1"); 35 public static final HashType SHA224 = new HashType("SHA224"); 36 public static final HashType SHA256 = new HashType("SHA256"); 37 public static final HashType SHA384 = new HashType("SHA384"); 38 public static final HashType SHA512 = new HashType("SHA512"); 39 40 private final String name; 41 HashType(String name)42 private HashType(String name) { 43 this.name = name; 44 } 45 46 @Override toString()47 public String toString() { 48 return name; 49 } 50 } 51 52 /** Builder for HkdfPrfParameters. */ 53 public static final class Builder { 54 @Nullable private Integer keySizeBytes = null; 55 @Nullable private HashType hashType = null; 56 @Nullable private Bytes salt = null; 57 Builder()58 private Builder() {} 59 60 @CanIgnoreReturnValue setKeySizeBytes(int keySizeBytes)61 public Builder setKeySizeBytes(int keySizeBytes) throws GeneralSecurityException { 62 if (keySizeBytes < MIN_KEY_SIZE) { 63 throw new InvalidAlgorithmParameterException( 64 String.format( 65 "Invalid key size %d; only 128-bit or larger are supported", keySizeBytes * 8)); 66 } 67 this.keySizeBytes = keySizeBytes; 68 return this; 69 } 70 71 @CanIgnoreReturnValue setHashType(HashType hashType)72 public Builder setHashType(HashType hashType) { 73 this.hashType = hashType; 74 return this; 75 } 76 77 @CanIgnoreReturnValue setSalt(Bytes salt)78 public Builder setSalt(Bytes salt) { 79 if (salt.size() == 0) { 80 this.salt = null; 81 return this; 82 } 83 this.salt = salt; 84 return this; 85 } 86 build()87 public HkdfPrfParameters build() throws GeneralSecurityException { 88 if (keySizeBytes == null) { 89 throw new GeneralSecurityException("key size is not set"); 90 } 91 if (hashType == null) { 92 throw new GeneralSecurityException("hash type is not set"); 93 } 94 return new HkdfPrfParameters(keySizeBytes, hashType, salt); 95 } 96 } 97 98 private final int keySizeBytes; 99 private final HashType hashType; 100 @Nullable private final Bytes salt; 101 HkdfPrfParameters(int keySizeBytes, HashType hashType, Bytes salt)102 private HkdfPrfParameters(int keySizeBytes, HashType hashType, Bytes salt) { 103 this.keySizeBytes = keySizeBytes; 104 this.hashType = hashType; 105 this.salt = salt; 106 } 107 builder()108 public static Builder builder() { 109 return new Builder(); 110 } 111 getKeySizeBytes()112 public int getKeySizeBytes() { 113 return keySizeBytes; 114 } 115 getHashType()116 public HashType getHashType() { 117 return hashType; 118 } 119 120 /** 121 * Gets the salt value, which defaults to null if not set, as per RFC 5869. The HKDF PRF 122 * implementation must convert a null salt to a string of zeros that is the length of the hash 123 * function output. 124 */ 125 @Nullable getSalt()126 public Bytes getSalt() { 127 return salt; 128 } 129 130 @Override equals(Object o)131 public boolean equals(Object o) { 132 if (!(o instanceof HkdfPrfParameters)) { 133 return false; 134 } 135 HkdfPrfParameters that = (HkdfPrfParameters) o; 136 return that.getKeySizeBytes() == getKeySizeBytes() 137 && that.getHashType() == getHashType() 138 && Objects.equals(that.getSalt(), getSalt()); 139 } 140 141 @Override hashCode()142 public int hashCode() { 143 return Objects.hash(HkdfPrfParameters.class, keySizeBytes, hashType, salt); 144 } 145 146 @Override hasIdRequirement()147 public boolean hasIdRequirement() { 148 return false; 149 } 150 151 @Override toString()152 public String toString() { 153 return "HKDF PRF Parameters (hashType: " 154 + hashType 155 + ", salt: " 156 + salt 157 + ", and " 158 + keySizeBytes 159 + "-byte key)"; 160 } 161 } 162