1# Copyright 2019 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"""EC based commutative cipher.""" 16 17from typing import Optional 18 19from private_join_and_compute.py.crypto_util import elliptic_curve 20from private_join_and_compute.py.crypto_util import supported_hashes 21 22NID_secp224r1 = 713 # pylint: disable=invalid-name 23DEFAULT_CURVE_ID = NID_secp224r1 24POINT_CONVERSION_COMPRESSED = 2 25 26 27class EcCipher(object): 28 """A commutative cipher based on Elliptic Curves.""" 29 30 # key is an address. 31 def __init__( 32 self, 33 curve_id: int = DEFAULT_CURVE_ID, 34 private_key_bytes: Optional[bytes] = None, 35 hash_type: Optional[supported_hashes.HashType] = None, 36 ) -> None: 37 """Generate a new EC key pair, if the key is not passed as a parameter. 38 39 The private key is a random value and the private point is the result of 40 performing a scalar point multiplication of that value with the curve's 41 base point. 42 43 Args: 44 curve_id: the id of the curve to use, given as an int value. 45 private_key_bytes: an ec key in bytes, if the key has already been 46 generated. 47 hash_type: the hash to use in order to map a string to the elliptic curve. 48 49 Raises: 50 TypeError: If curve_id is not an int. 51 Exception: If the key could not be generated. 52 """ 53 self._ec_key = elliptic_curve.ECKey(curve_id, private_key_bytes, hash_type) 54 55 def Encrypt(self, id_bytes: bytes) -> bytes: 56 """Hashes the client id to a point on the curve. 57 58 It then encrypts the point by multiplying it with the private key. 59 60 Args: 61 id_bytes: a client id encoded as a string/byte value. 62 63 Returns: 64 the compressed encoded EC Point in bytes. 65 66 Raises: 67 TypeError: If id_bytes is not a str type. 68 """ 69 ec_point = self._ec_key.elliptic_curve.GetPointByHashingToCurve(id_bytes) 70 return self.EncryptPoint(ec_point) 71 72 def EncryptPoint(self, ec_point) -> bytes: 73 """Encrypts a point on the curve. 74 75 Args: 76 ec_point: the point to encrypt. 77 78 Returns: 79 the compressed encoded encrypted point in bytes 80 """ 81 ec_point *= self._ec_key.priv_key_bn 82 return ec_point.GetAsBytes() 83 84 def ReEncrypt(self, enc_id_bytes: bytes) -> bytes: 85 """Re-encrypts the id by multiplying with the private key. 86 87 Args: 88 enc_id_bytes: an encrypted client id as a bytes value. 89 90 Returns: 91 the compressed encoded re-encrypted EC Point in bytes. 92 93 Raises: 94 TypeError: If enc_id_bytes id is not a str type. 95 """ 96 ec_point = self._ec_key.elliptic_curve.GetPointFromBytes(enc_id_bytes) 97 return self.EncryptPoint(ec_point) 98 99 @property 100 def ec_key(self): 101 return self._ec_key 102 103 @property 104 def elliptic_curve(self): 105 return self._ec_key.elliptic_curve 106 107 def DecryptReEncryptedId(self, reenc_id_bytes: bytes) -> bytes: 108 """Decrypts a reencrypted id to its encrypted id form. 109 110 Assuming reenc_id_bytes=E_k1(E_k2(m)) where E(.) is the ec_cipher and k1/k2 111 are private keys. This function with decryption key, k1', returns E_k2(m) or 112 with decryption key, k2', E_k1(m). Essentially this removes one layer of 113 encryption from the reenc_id_bytes. 114 115 This function *cannot* be applied to encrypted ids as the return value would 116 be the message one-way hashed to a point on the curve. 117 118 Args: 119 reenc_id_bytes: a reencrypted client id, encoded with a key and then 120 reencoded with another key. 121 122 Returns: 123 An encoded id in bytes. 124 """ 125 ec_point = self._ec_key.elliptic_curve.GetPointFromBytes(reenc_id_bytes) 126 ec_point *= self._ec_key.decrypt_key_bignum 127 return ec_point.GetAsBytes() 128