• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 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  *     https://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 package com.google.security.cryptauth.lib.securegcm;
16 
17 import com.google.protobuf.InvalidProtocolBufferException;
18 import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
19 import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.GenericPublicKey;
20 import java.security.KeyFactory;
21 import java.security.NoSuchAlgorithmException;
22 import java.security.PrivateKey;
23 import java.security.PublicKey;
24 import java.security.interfaces.ECPrivateKey;
25 import java.security.interfaces.ECPublicKey;
26 import java.security.spec.InvalidKeySpecException;
27 import java.security.spec.PKCS8EncodedKeySpec;
28 import javax.crypto.SecretKey;
29 import javax.crypto.interfaces.DHPrivateKey;
30 import javax.crypto.spec.SecretKeySpec;
31 
32 /**
33  * Utility class for encoding and parsing keys used by SecureGcm.
34  */
35 public class KeyEncoding {
KeyEncoding()36   private KeyEncoding() {} // Do not instantiate
37 
38   private static boolean simulateLegacyCryptoRequired = false;
39 
40   /**
41    * The JCA algorithm name to use when encoding/decoding symmetric keys.
42    */
43   static final String SYMMETRIC_KEY_ENCODING_ALG = "AES";
44 
encodeMasterKey(SecretKey masterKey)45   public static byte[] encodeMasterKey(SecretKey masterKey) {
46     return masterKey.getEncoded();
47   }
48 
parseMasterKey(byte[] encodedMasterKey)49   public static SecretKey parseMasterKey(byte[] encodedMasterKey) {
50     return new SecretKeySpec(encodedMasterKey, SYMMETRIC_KEY_ENCODING_ALG);
51   }
52 
encodeUserPublicKey(PublicKey pk)53   public static byte[] encodeUserPublicKey(PublicKey pk) {
54     return encodePublicKey(pk);
55   }
56 
encodeUserPrivateKey(PrivateKey sk)57   public static byte[] encodeUserPrivateKey(PrivateKey sk) {
58     return sk.getEncoded();
59   }
60 
parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy)61   public static PrivateKey parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy)
62       throws InvalidKeySpecException {
63     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
64     if (isLegacy) {
65       return getRsaKeyFactory().generatePrivate(keySpec);
66     }
67     return getEcKeyFactory().generatePrivate(keySpec);
68   }
69 
parseUserPublicKey(byte[] keyBytes)70   public static PublicKey parseUserPublicKey(byte[] keyBytes) throws InvalidKeySpecException {
71     return parsePublicKey(keyBytes);
72   }
73 
encodeKeyAgreementPublicKey(PublicKey pk)74   public static byte[] encodeKeyAgreementPublicKey(PublicKey pk) {
75     return encodePublicKey(pk);
76   }
77 
parseKeyAgreementPublicKey(byte[] keyBytes)78   public static PublicKey parseKeyAgreementPublicKey(byte[] keyBytes)
79       throws InvalidKeySpecException {
80     return parsePublicKey(keyBytes);
81   }
82 
encodeKeyAgreementPrivateKey(PrivateKey sk)83   public static byte[] encodeKeyAgreementPrivateKey(PrivateKey sk) {
84     if (isLegacyPrivateKey(sk)) {
85       return PublicKeyProtoUtil.encodeDh2048PrivateKey((DHPrivateKey) sk);
86     }
87     return sk.getEncoded();
88   }
89 
parseKeyAgreementPrivateKey(byte[] keyBytes, boolean isLegacy)90   public static PrivateKey parseKeyAgreementPrivateKey(byte[] keyBytes, boolean isLegacy)
91       throws InvalidKeySpecException {
92     if (isLegacy) {
93       return PublicKeyProtoUtil.parseDh2048PrivateKey(keyBytes);
94     }
95     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
96     return getEcKeyFactory().generatePrivate(keySpec);
97   }
98 
encodeSigningPublicKey(PublicKey pk)99   public static byte[] encodeSigningPublicKey(PublicKey pk) {
100     return encodePublicKey(pk);
101   }
102 
parseSigningPublicKey(byte[] keyBytes)103   public static PublicKey parseSigningPublicKey(byte[] keyBytes) throws InvalidKeySpecException {
104     return parsePublicKey(keyBytes);
105   }
106 
encodeSigningPrivateKey(PrivateKey sk)107   public static byte[] encodeSigningPrivateKey(PrivateKey sk) {
108     return sk.getEncoded();
109   }
110 
parseSigningPrivateKey(byte[] keyBytes)111   public static PrivateKey parseSigningPrivateKey(byte[] keyBytes) throws InvalidKeySpecException {
112     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
113     return getEcKeyFactory().generatePrivate(keySpec);
114   }
115 
isLegacyPublicKey(PublicKey pk)116   public static boolean isLegacyPublicKey(PublicKey pk) {
117     if (pk instanceof ECPublicKey) {
118       return false;
119     }
120     return true;
121   }
122 
isLegacyPrivateKey(PrivateKey sk)123   public static boolean isLegacyPrivateKey(PrivateKey sk) {
124     if (sk instanceof ECPrivateKey) {
125       return false;
126     }
127     return true;
128   }
129 
isLegacyCryptoRequired()130   public static boolean isLegacyCryptoRequired() {
131     return PublicKeyProtoUtil.isLegacyCryptoRequired() || simulateLegacyCryptoRequired;
132   }
133 
134   /**
135    * When testing, use this to force {@link #isLegacyCryptoRequired()} to return {@code true}
136    */
137   // @VisibleForTesting
setSimulateLegacyCrypto(boolean forceLegacy)138   public static void setSimulateLegacyCrypto(boolean forceLegacy) {
139     simulateLegacyCryptoRequired = forceLegacy;
140   }
141 
encodePublicKey(PublicKey pk)142   private static byte[] encodePublicKey(PublicKey pk) {
143     return PublicKeyProtoUtil.encodePublicKey(pk).toByteArray();
144   }
145 
parsePublicKey(byte[] keyBytes)146   private static PublicKey parsePublicKey(byte[] keyBytes) throws InvalidKeySpecException {
147     try {
148       return PublicKeyProtoUtil.parsePublicKey(GenericPublicKey.parseFrom(keyBytes));
149     } catch (InvalidProtocolBufferException e) {
150       throw new InvalidKeySpecException("Unable to parse GenericPublicKey", e);
151     } catch (IllegalArgumentException e) {
152       throw new InvalidKeySpecException("Unable to parse GenericPublicKey", e);
153     }
154   }
155 
getEcKeyFactory()156   static KeyFactory getEcKeyFactory() {
157     try {
158       return KeyFactory.getInstance("EC");
159     } catch (NoSuchAlgorithmException e) {
160       throw new RuntimeException(e);  // No ECDH provider available
161     }
162   }
163 
getRsaKeyFactory()164   static KeyFactory getRsaKeyFactory() {
165     try {
166       return KeyFactory.getInstance("RSA");
167     } catch (NoSuchAlgorithmException e) {
168       throw new RuntimeException(e);  // No RSA provider available
169     }
170   }
171 }
172