1 package com.google.privacy.private_join_and_compute.encryption.commutative;
2 
3 import com.google.common.annotations.VisibleForTesting;
4 import com.google.common.hash.Hashing;
5 import com.google.common.primitives.Bytes;
6 import java.math.BigInteger;
7 import java.security.KeyFactory;
8 import java.security.KeyPairGenerator;
9 import java.security.NoSuchAlgorithmException;
10 import java.security.SecureRandom;
11 import java.security.interfaces.ECPrivateKey;
12 import java.security.spec.ECParameterSpec;
13 import java.security.spec.ECPoint;
14 import java.security.spec.ECPrivateKeySpec;
15 import java.security.spec.InvalidKeySpecException;
16 
17 /**
18  * EcCommutativeCipher class with the property that K1(K2(a)) = K2(K1(a)) where K(a) is encryption
19  * with the key K.
20  *
21  * <p>This class allows two parties to determine if they share the same value, without revealing the
22  * sensitive value to each other. See the paper "Using Commutative Encryption to Share a Secret" at
23  * https://eprint.iacr.org/2008/356.pdf for reference.
24  *
25  * <p>The encryption is performed over an elliptic curve.
26  *
27  * <p>Security: The provided bit security is half the number of bits of the underlying curve. For
28  * example, using curve secp160r1 gives 80 bit security.
29  */
30 public abstract class EcCommutativeCipherBase {
31   /** List of supported underlying hash types for the commutative cipher. */
32   public enum HashType {
33     SHA256(256),
34     SHA384(384),
35     SHA512(512);
36 
37     private final int hashBitLength;
38 
HashType(int hashBitLength)39     private HashType(int hashBitLength) {
40       this.hashBitLength = hashBitLength;
41     }
42 
43     /** Returns the bit length. */
getHashBitLength()44     public int getHashBitLength() {
45       return hashBitLength;
46     }
47   }
48 
49   // EC classes are conceptually immutable even though the class is not annotated accordingly.
50   @SuppressWarnings("Immutable")
51   protected final ECPrivateKey privateKey;
52 
53   @SuppressWarnings("Immutable")
54   protected final SupportedCurve ecCurve;
55 
56   protected final HashType hashType;
57 
58   /** Creates an EcCommutativeCipherBase object with the given private key and curve. */
EcCommutativeCipherBase(HashType hashType, ECPrivateKey key, SupportedCurve ecCurve)59   protected EcCommutativeCipherBase(HashType hashType, ECPrivateKey key, SupportedCurve ecCurve) {
60     this.privateKey = key;
61     this.ecCurve = ecCurve;
62     this.hashType = hashType;
63   }
64 
65   /** Decodes the private key from BigInteger. */
decodePrivateKey(BigInteger key, SupportedCurve curve)66   protected static ECPrivateKey decodePrivateKey(BigInteger key, SupportedCurve curve)
67       throws InvalidKeySpecException {
68     checkPrivateKey(key, curve.getParameterSpec());
69     ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(key, curve.getParameterSpec());
70     try {
71       KeyFactory keyFactory = KeyFactory.getInstance("EC");
72       return (ECPrivateKey) keyFactory.generatePrivate(privateKeySpec);
73     } catch (NoSuchAlgorithmException e) {
74       throw new AssertionError(e);
75     }
76   }
77 
78   /** Creates a new random private key. */
createPrivateKey(SupportedCurve curve)79   protected static ECPrivateKey createPrivateKey(SupportedCurve curve) {
80     try {
81       KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
82       generator.initialize(curve.getParameterSpec(), new SecureRandom());
83       return (ECPrivateKey) generator.generateKeyPair().getPrivate();
84     } catch (Exception e) {
85       throw new AssertionError(e);
86     }
87   }
88 
89   /**
90    * Encrypts an input with the private key, first hashing the input to the curve.
91    *
92    * @param plaintext bytes to encrypt
93    * @return an encoded point in compressed form as defined in ANSI X9.62 ECDSA.
94    */
encrypt(byte[] plaintext)95   public abstract byte[] encrypt(byte[] plaintext);
96 
97   /**
98    * Re-encrypts an encoded point with the private key.
99    *
100    * @param ciphertext an encoded point as defined in ANSI X9.62 ECDSA
101    * @return an encoded point in compressed form as defined in ANSI X9.62 ECDSA
102    */
reEncrypt(byte[] ciphertext)103   public abstract byte[] reEncrypt(byte[] ciphertext);
104 
105   /**
106    * Decrypts an encoded point that has been previously encrypted with the private key. Does not
107    * reverse hashing to the curve.
108    *
109    * @param ciphertext an encoded point as defined in ANSI X9.62 ECDSA
110    * @return an encoded point in compressed form as defined in ANSI X9.62 ECDSA
111    */
decrypt(byte[] ciphertext)112   public abstract byte[] decrypt(byte[] ciphertext);
113 
114   /**
115    * Hashes bytes to a point on the elliptic curve y^2 = x^3 + ax + b over a prime field.
116    */
117   @VisibleForTesting
hashIntoTheCurveInternal(byte[] byteId)118   abstract ECPoint hashIntoTheCurveInternal(byte[] byteId);
119 
120   /**
121    * Hashes bytes to a point on the elliptic curve y^2 = x^3 + ax + b over a prime field. All
122    * implementations must match the C++ version:
123    *
124    * <p>The resulting point is returned encoded in compressed form as defined in ANSI X9.62 ECDSA.
125    */
hashIntoTheCurve(byte[] byteId)126   public abstract byte[] hashIntoTheCurve(byte[] byteId);
127 
128   /**
129    * A random oracle function mapping x deterministically into a large domain.
130    *
131    * <p>// copybara:strip_begin(Remove internal comment)
132    *
133    * <p>The random oracle is similar to the example given in the last paragraph of Chapter 6 of [1]
134    * where the output is expanded by successively hashing the concatenation of the input with a
135    * fixed sized counter starting from 1.
136    *
137    * <p>[1] Bellare, Mihir, and Phillip Rogaway. "Random oracles are practical: A paradigm for
138    * designing efficient protocols." Proceedings of the 1st ACM conference on Computer and
139    * communications security. ACM, 1993.
140    *
141    * <p>Returns a value from the set [0, max_value).
142    *
143    * <p>Check Error: if bit length of max_value is greater than 130048. Since the counter used for
144    * expanding the output is expanded to 8 bit length (hard-coded), any counter value that is
145    * greater than 512 would cause variable length inputs passed to the underlying
146    * sha256/sha384/sha512 calls and might make this random oracle's output not uniform across the
147    * output domain.
148    *
149    * <p>The output length is increased by a security value of 256 which reduces the bias of
150    * selecting certain values more often than others when max_value is not a multiple of 2.
151    */
randomOracle(byte[] bytes, BigInteger maxValue, HashType hashType)152   public static BigInteger randomOracle(byte[] bytes, BigInteger maxValue, HashType hashType) {
153     int hashBitLength = hashType.getHashBitLength();
154     int outputBitLength = maxValue.bitLength() + hashBitLength;
155     int iterCount = (outputBitLength + hashBitLength - 1) / hashBitLength;
156     int excessBitCount = (iterCount * hashBitLength) - outputBitLength;
157     BigInteger hashOutput = BigInteger.ZERO;
158     BigInteger counter = BigInteger.ONE;
159     for (int i = 1; i < iterCount + 1; ++i) {
160       hashOutput = hashOutput.shiftLeft(hashBitLength);
161       byte[] counterBytes = bigIntegerToByteArrayCppCompatible(counter);
162       byte[] hashInput = Bytes.concat(counterBytes, bytes);
163       byte[] hashCode;
164       switch (hashType) {
165         case SHA256:
166           hashCode = Hashing.sha256().hashBytes(hashInput).asBytes();
167           break;
168         case SHA384:
169           hashCode = Hashing.sha384().hashBytes(hashInput).asBytes();
170           break;
171         default:
172           hashCode = Hashing.sha512().hashBytes(hashInput).asBytes();
173       }
174       hashOutput = hashOutput.add(byteArrayToBigIntegerCppCompatible(hashCode));
175       counter = counter.add(BigInteger.ONE);
176     }
177     return hashOutput.shiftRight(excessBitCount).mod(maxValue);
178   }
179 
180   /** Checks the private key is between 1 and the order of the group. */
checkPrivateKey(BigInteger key, ECParameterSpec params)181   private static void checkPrivateKey(BigInteger key, ECParameterSpec params) {
182     if (key.compareTo(BigInteger.ONE) <= 0 || key.compareTo(params.getOrder()) >= 0) {
183       throw new IllegalArgumentException("The given key is out of bounds.");
184     }
185   }
186 
187   /**
188    * Returns the private key bytes.
189    *
190    * @return the private key bytes for this EcCommutativeCipher.
191    */
getPrivateKeyBytes()192   public byte[] getPrivateKeyBytes() {
193     return bigIntegerToByteArrayCppCompatible(privateKey.getS());
194   }
195 
196   // copybara:strip_begin(Remove deprecated functions)
197   /**
198    * Returns the private key bytes.
199    *
200    * @deprecated This function is incompatible with the C++ implementation.
201    * @return the private key bytes for this EcCommutativeCipher.
202    */
203   @Deprecated
getPrivateKeyBytesCppIncompatible()204   public byte[] getPrivateKeyBytesCppIncompatible() {
205     return privateKey.getS().toByteArray();
206   }
207   // copybara:strip_end
208 
209   /**
210    * This function converts a BigInteger into a byte array in big-endian form without two's
211    * complement representation. This function is compatible with C++ OpenSSL's BigNum
212    * implementation.
213    */
bigIntegerToByteArrayCppCompatible(BigInteger value)214   public static byte[] bigIntegerToByteArrayCppCompatible(BigInteger value) {
215     byte[] signedArray = value.toByteArray();
216     int leadingZeroes = 0;
217     while (signedArray[leadingZeroes] == 0) {
218       leadingZeroes++;
219     }
220     byte[] unsignedArray = new byte[signedArray.length - leadingZeroes];
221     System.arraycopy(signedArray, leadingZeroes, unsignedArray, 0, unsignedArray.length);
222     return unsignedArray;
223   }
224 
225   /**
226    * This function converts bytes to BigInteger. The input bytes are assumed to be in big-endian
227    * form. The function converts the bytes into two's complement big-endian form before converting
228    * into a BigInteger. This function matches the C++ OpenSSL implementation of bytes to BigNum.
229    */
byteArrayToBigIntegerCppCompatible(byte[] bytes)230   public static BigInteger byteArrayToBigIntegerCppCompatible(byte[] bytes) {
231     byte[] twosComplement = new byte[bytes.length + 1];
232     twosComplement[0] = 0;
233     System.arraycopy(bytes, 0, twosComplement, 1, bytes.length);
234     return new BigInteger(twosComplement);
235   }
236 
237   /**
238    * Encodes a point.
239    *
240    * @param point a point to encode
241    * @return an encoded point in compressed form as defined in ANSI X9.62 ECDSA.
242    */
243   @VisibleForTesting
getEncoded(ECPoint point)244   abstract byte[] getEncoded(ECPoint point);
245 
246   /**
247    * Checks validity of a point.
248    *
249    * @param point a point to check
250    * @return true iff point is valid.
251    */
252   @VisibleForTesting
isValid(ECPoint point)253   abstract boolean isValid(ECPoint point);
254 
255   /**
256    * Checks whether a point is at infinity.
257    *
258    * @param point a point to check
259    * @return true iff point is infinity.
260    */
261   @VisibleForTesting
isInfinity(ECPoint point)262   abstract boolean isInfinity(ECPoint point);
263 }
264 
265