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 com.google.crypto.tink.AccessesPartialKey; 20 import com.google.crypto.tink.HybridEncrypt; 21 import com.google.crypto.tink.hybrid.EciesParameters; 22 import com.google.crypto.tink.hybrid.EciesPublicKey; 23 import com.google.crypto.tink.hybrid.internal.EciesDemHelper; 24 import com.google.crypto.tink.internal.EnumTypeProtoConverter; 25 import com.google.crypto.tink.subtle.EllipticCurves.PointFormatType; 26 import java.security.GeneralSecurityException; 27 import java.security.interfaces.ECPublicKey; 28 29 /** 30 * ECIES encryption with HKDF-KEM (key encapsulation mechanism) and AEAD-DEM (data encapsulation 31 * mechanism). 32 * 33 * @since 1.0.0 34 */ 35 public final class EciesAeadHkdfHybridEncrypt implements HybridEncrypt { 36 private final EciesHkdfSenderKem senderKem; 37 private final String hkdfHmacAlgo; 38 private final byte[] hkdfSalt; 39 private final EllipticCurves.PointFormatType ecPointFormat; 40 private final EciesDemHelper.Dem dem; 41 private final byte[] outputPrefix; 42 toHmacAlgo(EciesParameters.HashType hash)43 static final String toHmacAlgo(EciesParameters.HashType hash) throws GeneralSecurityException { 44 if (hash.equals(EciesParameters.HashType.SHA1)) { 45 return "HmacSha1"; 46 } 47 if (hash.equals(EciesParameters.HashType.SHA224)) { 48 return "HmacSha224"; 49 } 50 if (hash.equals(EciesParameters.HashType.SHA256)) { 51 return "HmacSha256"; 52 } 53 if (hash.equals(EciesParameters.HashType.SHA384)) { 54 return "HmacSha384"; 55 } 56 if (hash.equals(EciesParameters.HashType.SHA512)) { 57 return "HmacSha512"; 58 } 59 throw new GeneralSecurityException("hash unsupported for EciesAeadHkdf: " + hash); 60 } 61 62 static final EnumTypeProtoConverter<EllipticCurves.CurveType, EciesParameters.CurveType> 63 CURVE_TYPE_CONVERTER = 64 EnumTypeProtoConverter.<EllipticCurves.CurveType, EciesParameters.CurveType>builder() 65 .add(EllipticCurves.CurveType.NIST_P256, EciesParameters.CurveType.NIST_P256) 66 .add(EllipticCurves.CurveType.NIST_P384, EciesParameters.CurveType.NIST_P384) 67 .add(EllipticCurves.CurveType.NIST_P521, EciesParameters.CurveType.NIST_P521) 68 .build(); 69 70 static final EnumTypeProtoConverter<EllipticCurves.PointFormatType, EciesParameters.PointFormat> 71 POINT_FORMAT_TYPE_CONVERTER = 72 EnumTypeProtoConverter 73 .<EllipticCurves.PointFormatType, EciesParameters.PointFormat>builder() 74 .add(PointFormatType.UNCOMPRESSED, EciesParameters.PointFormat.UNCOMPRESSED) 75 .add(PointFormatType.COMPRESSED, EciesParameters.PointFormat.COMPRESSED) 76 .add( 77 PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED, 78 EciesParameters.PointFormat.LEGACY_UNCOMPRESSED) 79 .build(); 80 EciesAeadHkdfHybridEncrypt( final ECPublicKey recipientPublicKey, final byte[] hkdfSalt, String hkdfHmacAlgo, EllipticCurves.PointFormatType ecPointFormat, EciesDemHelper.Dem dem, byte[] outputPrefix)81 private EciesAeadHkdfHybridEncrypt( 82 final ECPublicKey recipientPublicKey, 83 final byte[] hkdfSalt, 84 String hkdfHmacAlgo, 85 EllipticCurves.PointFormatType ecPointFormat, 86 EciesDemHelper.Dem dem, 87 byte[] outputPrefix) 88 throws GeneralSecurityException { 89 EllipticCurves.checkPublicKey(recipientPublicKey); 90 this.senderKem = new EciesHkdfSenderKem(recipientPublicKey); 91 this.hkdfSalt = hkdfSalt; 92 this.hkdfHmacAlgo = hkdfHmacAlgo; 93 this.ecPointFormat = ecPointFormat; 94 this.dem = dem; 95 this.outputPrefix = outputPrefix; 96 } 97 98 @AccessesPartialKey create(EciesPublicKey key)99 public static HybridEncrypt create(EciesPublicKey key) throws GeneralSecurityException { 100 EllipticCurves.CurveType curveType = 101 CURVE_TYPE_CONVERTER.toProtoEnum(key.getParameters().getCurveType()); 102 ECPublicKey recipientPublicKey = 103 EllipticCurves.getEcPublicKey( 104 curveType, 105 key.getNistCurvePoint().getAffineX().toByteArray(), 106 key.getNistCurvePoint().getAffineY().toByteArray()); 107 byte[] hkdfSalt = new byte[0]; 108 if (key.getParameters().getSalt() != null) { 109 hkdfSalt = key.getParameters().getSalt().toByteArray(); 110 } 111 return new EciesAeadHkdfHybridEncrypt( 112 recipientPublicKey, 113 hkdfSalt, 114 toHmacAlgo(key.getParameters().getHashType()), 115 POINT_FORMAT_TYPE_CONVERTER.toProtoEnum(key.getParameters().getNistCurvePointFormat()), 116 EciesDemHelper.getDem(key.getParameters()), 117 key.getOutputPrefix().toByteArray()); 118 } 119 120 /** 121 * Encrypts {@code plaintext} using {@code contextInfo} as <b>info</b>-parameter of the underlying 122 * HKDF. 123 * 124 * @return resulting ciphertext. 125 */ 126 @Override encrypt(final byte[] plaintext, final byte[] contextInfo)127 public byte[] encrypt(final byte[] plaintext, final byte[] contextInfo) 128 throws GeneralSecurityException { 129 EciesHkdfSenderKem.KemKey kemKey = 130 senderKem.generateKey( 131 hkdfHmacAlgo, hkdfSalt, contextInfo, dem.getSymmetricKeySizeInBytes(), ecPointFormat); 132 return dem.encrypt(kemKey.getSymmetricKey(), outputPrefix, kemKey.getKemBytes(), plaintext); 133 } 134 } 135