• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.google.crypto.tink.internal.Util.isPrefix;
20 
21 import com.google.crypto.tink.AccessesPartialKey;
22 import com.google.crypto.tink.HybridDecrypt;
23 import com.google.crypto.tink.InsecureSecretKeyAccess;
24 import com.google.crypto.tink.hybrid.EciesPrivateKey;
25 import com.google.crypto.tink.hybrid.internal.EciesDemHelper;
26 import com.google.crypto.tink.internal.BigIntegerEncoding;
27 import java.security.GeneralSecurityException;
28 import java.security.interfaces.ECPrivateKey;
29 import java.security.spec.EllipticCurve;
30 import java.util.Arrays;
31 
32 /**
33  * ECIES encryption with HKDF-KEM (key encapsulation mechanism) and AEAD-DEM (data encapsulation
34  * mechanism).
35  *
36  * @since 1.0.0
37  */
38 public final class EciesAeadHkdfHybridDecrypt implements HybridDecrypt {
39   private final ECPrivateKey recipientPrivateKey;
40   private final EciesHkdfRecipientKem recipientKem;
41   private final String hkdfHmacAlgo;
42   private final byte[] hkdfSalt;
43   private final EllipticCurves.PointFormatType ecPointFormat;
44   private final EciesDemHelper.Dem dem;
45   private final byte[] outputPrefix;
46 
EciesAeadHkdfHybridDecrypt( final ECPrivateKey recipientPrivateKey, final byte[] hkdfSalt, String hkdfHmacAlgo, EllipticCurves.PointFormatType ecPointFormat, EciesDemHelper.Dem dem, byte[] outputPrefix)47   private EciesAeadHkdfHybridDecrypt(
48       final ECPrivateKey recipientPrivateKey,
49       final byte[] hkdfSalt,
50       String hkdfHmacAlgo,
51       EllipticCurves.PointFormatType ecPointFormat,
52       EciesDemHelper.Dem dem,
53       byte[] outputPrefix) {
54     this.recipientPrivateKey = recipientPrivateKey;
55     this.recipientKem = new EciesHkdfRecipientKem(recipientPrivateKey);
56     this.hkdfSalt = hkdfSalt;
57     this.hkdfHmacAlgo = hkdfHmacAlgo;
58     this.ecPointFormat = ecPointFormat;
59     this.dem = dem;
60     this.outputPrefix = outputPrefix;
61   }
62 
63   @AccessesPartialKey
create(EciesPrivateKey key)64   public static HybridDecrypt create(EciesPrivateKey key) throws GeneralSecurityException {
65     EllipticCurves.CurveType curveType =
66         EciesAeadHkdfHybridEncrypt.CURVE_TYPE_CONVERTER.toProtoEnum(
67             key.getParameters().getCurveType());
68     ECPrivateKey recipientPrivateKey =
69         EllipticCurves.getEcPrivateKey(
70             curveType,
71             BigIntegerEncoding.toBigEndianBytes(
72                 key.getNistPrivateKeyValue().getBigInteger(InsecureSecretKeyAccess.get())));
73     byte[] hkdfSalt = new byte[0];
74     if (key.getParameters().getSalt() != null) {
75       hkdfSalt = key.getParameters().getSalt().toByteArray();
76     }
77     return new EciesAeadHkdfHybridDecrypt(
78         recipientPrivateKey,
79         hkdfSalt,
80         EciesAeadHkdfHybridEncrypt.toHmacAlgo(key.getParameters().getHashType()),
81         EciesAeadHkdfHybridEncrypt.POINT_FORMAT_TYPE_CONVERTER.toProtoEnum(
82             key.getParameters().getNistCurvePointFormat()),
83         EciesDemHelper.getDem(key.getParameters()),
84         key.getOutputPrefix().toByteArray());
85   }
86 
87   @Override
decrypt(final byte[] ciphertext, final byte[] contextInfo)88   public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo)
89       throws GeneralSecurityException {
90     if (!isPrefix(outputPrefix, ciphertext)) {
91       throw new GeneralSecurityException("Invalid ciphertext (output prefix mismatch)");
92     }
93     int prefixSize = outputPrefix.length;
94     EllipticCurve curve = recipientPrivateKey.getParams().getCurve();
95     int headerSize = EllipticCurves.encodingSizeInBytes(curve, ecPointFormat);
96     if (ciphertext.length < prefixSize + headerSize) {
97       throw new GeneralSecurityException("ciphertext too short");
98     }
99     byte[] kemBytes = Arrays.copyOfRange(ciphertext, prefixSize, prefixSize + headerSize);
100     byte[] symmetricKey =
101         recipientKem.generateKey(
102             kemBytes,
103             hkdfHmacAlgo,
104             hkdfSalt,
105             contextInfo,
106             dem.getSymmetricKeySizeInBytes(),
107             ecPointFormat);
108     return dem.decrypt(symmetricKey, ciphertext, prefixSize + headerSize);
109   }
110 }
111