1# 2# Copyright 2017 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16"""Methods to call native OpenSSL APIs to support P256 with compression. 17 18Since there are no Python crypto libraries that support P256 EC keys with 19with X9.62 compression, this module uses the native OpenSSL APIs to support 20key generation and deriving a shared secret using generated P256 EC keys. 21""" 22 23from ctypes import byref 24from ctypes import c_int 25from ctypes import c_ubyte 26from ctypes import c_uint 27from ctypes import cdll 28from ctypes import create_string_buffer 29from ctypes import POINTER 30from ctypes.util import find_library 31 32_ECDH_KEY_LEN = 33 33 34 35def _ec_helper_native(): 36 """Loads the ec_helper_native library. 37 38 Returns: 39 The ctypes ec_helper_native library. 40 """ 41 cdll.LoadLibrary(find_library('crypto')) 42 cdll.LoadLibrary(find_library('ssl')) 43 return cdll.LoadLibrary('./ec_helper_native.so') 44 45 46def generate_p256_key(): 47 """Geneates a new p256 key pair. 48 49 Raises: 50 RuntimeError: Generating a new key fails. 51 52 Returns: 53 A tuple containing the der-encoded private key and the X9.62 compressed 54 public key. 55 """ 56 ec_helper = _ec_helper_native() 57 native_generate_p256_key = ec_helper.generate_p256_key 58 native_generate_p256_key.argtypes = [ 59 POINTER(POINTER(c_ubyte)), 60 POINTER(c_uint), 61 POINTER(c_ubyte) 62 ] 63 native_generate_p256_key.restype = c_int 64 pub_key = (c_ubyte * _ECDH_KEY_LEN).from_buffer(bytearray(_ECDH_KEY_LEN)) 65 pub_key_ptr = POINTER(c_ubyte)(pub_key) 66 priv_key = POINTER(c_ubyte)() 67 priv_key_len = c_uint(0) 68 res = native_generate_p256_key( 69 byref(priv_key), byref(priv_key_len), pub_key_ptr) 70 if res != 0: 71 raise RuntimeError('Failed to generate EC key') 72 private_key = bytes(bytearray(priv_key[:priv_key_len.value])) 73 public_key = bytes(bytearray(pub_key[0:_ECDH_KEY_LEN])) 74 return [private_key, public_key] 75 76 77def compute_p256_shared_secret(private_key, device_public_key): 78 """Computes a shared secret between the script and the device. 79 80 Args: 81 private_key: the script's private key. 82 device_public_key: the device's public key. 83 84 Raises: 85 RuntimeError: Computing the shared secret fails. 86 87 Returns: 88 The shared secret. 89 """ 90 ec_helper = _ec_helper_native() 91 shared_secret_compute = ec_helper.shared_secret_compute 92 shared_secret_compute.argtypes = [ 93 POINTER(c_ubyte), c_uint, 94 POINTER(c_ubyte), 95 POINTER(c_ubyte) 96 ] 97 shared_secret_compute.restype = c_int 98 shared_secret = (c_ubyte * 32).from_buffer(bytearray(32)) 99 shared_secret_ptr = POINTER(c_ubyte)(shared_secret) 100 device_public_key_ptr = POINTER(c_ubyte)( 101 create_string_buffer(device_public_key)) 102 private_key_ptr = POINTER(c_ubyte)(create_string_buffer(private_key)) 103 res = shared_secret_compute(private_key_ptr, 104 len(private_key), device_public_key_ptr, 105 shared_secret_ptr) 106 if res != 0: 107 raise RuntimeError('Failed to compute P256 shared secret') 108 return bytes(bytearray(shared_secret[0:32])) 109