• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 
encodeDeviceSyncGroupPublicKey(PublicKey pk)61   public static byte[] encodeDeviceSyncGroupPublicKey(PublicKey pk) {
62     return PublicKeyProtoUtil.encodePaddedEcPublicKey(pk).toByteArray();
63   }
64 
parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy)65   public static PrivateKey parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy)
66       throws InvalidKeySpecException {
67     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
68     if (isLegacy) {
69       return getRsaKeyFactory().generatePrivate(keySpec);
70     }
71     return getEcKeyFactory().generatePrivate(keySpec);
72   }
73 
parseUserPublicKey(byte[] keyBytes)74   public static PublicKey parseUserPublicKey(byte[] keyBytes) throws InvalidKeySpecException {
75     return parsePublicKey(keyBytes);
76   }
77 
parseDeviceSyncGroupPublicKey(byte[] keyBytes)78   public static PublicKey parseDeviceSyncGroupPublicKey(byte[] keyBytes)
79       throws InvalidKeySpecException {
80     return parsePublicKey(keyBytes);
81   }
82 
encodeKeyAgreementPublicKey(PublicKey pk)83   public static byte[] encodeKeyAgreementPublicKey(PublicKey pk) {
84     return encodePublicKey(pk);
85   }
86 
parseKeyAgreementPublicKey(byte[] keyBytes)87   public static PublicKey parseKeyAgreementPublicKey(byte[] keyBytes)
88       throws InvalidKeySpecException {
89     return parsePublicKey(keyBytes);
90   }
91 
encodeKeyAgreementPrivateKey(PrivateKey sk)92   public static byte[] encodeKeyAgreementPrivateKey(PrivateKey sk) {
93     if (isLegacyPrivateKey(sk)) {
94       return PublicKeyProtoUtil.encodeDh2048PrivateKey((DHPrivateKey) sk);
95     }
96     return sk.getEncoded();
97   }
98 
parseKeyAgreementPrivateKey(byte[] keyBytes, boolean isLegacy)99   public static PrivateKey parseKeyAgreementPrivateKey(byte[] keyBytes, boolean isLegacy)
100       throws InvalidKeySpecException {
101     if (isLegacy) {
102       return PublicKeyProtoUtil.parseDh2048PrivateKey(keyBytes);
103     }
104     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
105     return getEcKeyFactory().generatePrivate(keySpec);
106   }
107 
encodeSigningPublicKey(PublicKey pk)108   public static byte[] encodeSigningPublicKey(PublicKey pk) {
109     return encodePublicKey(pk);
110   }
111 
parseSigningPublicKey(byte[] keyBytes)112   public static PublicKey parseSigningPublicKey(byte[] keyBytes) throws InvalidKeySpecException {
113     return parsePublicKey(keyBytes);
114   }
115 
encodeSigningPrivateKey(PrivateKey sk)116   public static byte[] encodeSigningPrivateKey(PrivateKey sk) {
117     return sk.getEncoded();
118   }
119 
parseSigningPrivateKey(byte[] keyBytes)120   public static PrivateKey parseSigningPrivateKey(byte[] keyBytes) throws InvalidKeySpecException {
121     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
122     return getEcKeyFactory().generatePrivate(keySpec);
123   }
124 
isLegacyPublicKey(PublicKey pk)125   public static boolean isLegacyPublicKey(PublicKey pk) {
126     if (pk instanceof ECPublicKey) {
127       return false;
128     }
129     return true;
130   }
131 
isLegacyPrivateKey(PrivateKey sk)132   public static boolean isLegacyPrivateKey(PrivateKey sk) {
133     if (sk instanceof ECPrivateKey) {
134       return false;
135     }
136     return true;
137   }
138 
isLegacyCryptoRequired()139   public static boolean isLegacyCryptoRequired() {
140     return PublicKeyProtoUtil.isLegacyCryptoRequired() || simulateLegacyCryptoRequired;
141   }
142 
143   /**
144    * When testing, use this to force {@link #isLegacyCryptoRequired()} to return {@code true}
145    */
146   // @VisibleForTesting
setSimulateLegacyCrypto(boolean forceLegacy)147   public static void setSimulateLegacyCrypto(boolean forceLegacy) {
148     simulateLegacyCryptoRequired = forceLegacy;
149   }
150 
encodePublicKey(PublicKey pk)151   private static byte[] encodePublicKey(PublicKey pk) {
152     return PublicKeyProtoUtil.encodePublicKey(pk).toByteArray();
153   }
154 
parsePublicKey(byte[] keyBytes)155   private static PublicKey parsePublicKey(byte[] keyBytes) throws InvalidKeySpecException {
156     try {
157       return PublicKeyProtoUtil.parsePublicKey(GenericPublicKey.parseFrom(keyBytes));
158     } catch (InvalidProtocolBufferException e) {
159       throw new InvalidKeySpecException("Unable to parse GenericPublicKey", e);
160     } catch (IllegalArgumentException e) {
161       throw new InvalidKeySpecException("Unable to parse GenericPublicKey", e);
162     }
163   }
164 
getEcKeyFactory()165   static KeyFactory getEcKeyFactory() {
166     try {
167       return KeyFactory.getInstance("EC");
168     } catch (NoSuchAlgorithmException e) {
169       throw new RuntimeException(e);  // No ECDH provider available
170     }
171   }
172 
getRsaKeyFactory()173   static KeyFactory getRsaKeyFactory() {
174     try {
175       return KeyFactory.getInstance("RSA");
176     } catch (NoSuchAlgorithmException e) {
177       throw new RuntimeException(e);  // No RSA provider available
178     }
179   }
180 }
181