Skip to content

Commit c21d650

Browse files
coord function
1 parent 6921600 commit c21d650

File tree

5 files changed

+93
-7
lines changed

5 files changed

+93
-7
lines changed

awscrt/crypto.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ class ECRawSignature(NamedTuple):
249249
r: bytes
250250
s: bytes
251251

252+
class ECPublicCoords(NamedTuple):
253+
x: bytes
254+
y: bytes
252255

253256
class EC(NativeResource):
254257
def __init__(self, binding):
@@ -293,6 +296,13 @@ def export_key(self, export_format: ECExportFormat) -> bytes:
293296
Exports the key in specified format.
294297
"""
295298
return _awscrt.ec_export_key(self._binding, export_format)
299+
300+
def get_public_coords(self, export_format: ECExportFormat) -> ECPublicCoords:
301+
"""
302+
Get public coords of the key
303+
"""
304+
(x, y) = _awscrt.ec_get_public_coords(self._binding, export_format)
305+
return ECPublicCoords(x=x, y=y)
296306

297307
def sign(self, digest: Union[bytes, bytearray, memoryview]) -> bytes:
298308
"""

setup.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,33 @@ def _build_dependencies(self):
375375

376376
self.library_dirs.insert(0, os.path.join(install_path, lib_dir))
377377

378+
def build_extension(self, ext):
379+
380+
# Warning: very hacky. feel free to replace with something cleaner
381+
# Problem: if you install python through homebrew, python config ldflags
382+
# will point to homebrew lib folder.
383+
# setuptools puts python ldflags before any of our lib paths, so if there is openssl or
384+
# another libcrypto in homebrew libs, it will get picked up before aws-lc we are building against.
385+
# And then we have fun failures due to lib mismatch.
386+
# I could not find a cleaner way, so lets just hook into linker command and make sure
387+
# our libs appear before other libs.
388+
if sys.platform == 'darwin' and using_libcrypto() and not using_system_libs() and not using_system_libcrypto():
389+
390+
orig_linker_so = self.compiler.linker_so[:]
391+
392+
for i, item in enumerate(self.compiler.linker_so):
393+
if item.startswith('-L'):
394+
self.compiler.linker_so[i:i] = [
395+
f"-L{item}" for item in self.library_dirs] + ['-Wl,-search_paths_first']
396+
break
397+
398+
try:
399+
super().build_extension(ext)
400+
finally:
401+
self.compiler.linker_so = orig_linker_so
402+
else:
403+
super().build_extension(ext)
404+
378405
def run(self):
379406
if using_system_libs():
380407
print("Skip building dependencies")

source/crypto.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ PyObject *aws_py_hash_update(PyObject *self, PyObject *args) {
110110
const char *to_hash_c_str;
111111
Py_ssize_t to_hash_len;
112112

113-
if (!PyArg_ParseTuple(args, "Os#", &hash_capsule, &to_hash_c_str, &to_hash_len)) {
113+
if (!PyArg_ParseTuple(args, "Oy#", &hash_capsule, &to_hash_c_str, &to_hash_len)) {
114114
return PyErr_AwsLastError();
115115
}
116116

@@ -179,7 +179,7 @@ PyObject *aws_py_sha256_hmac_new(PyObject *self, PyObject *args) {
179179
const char *secret_ptr;
180180
Py_ssize_t secret_len;
181181

182-
if (!PyArg_ParseTuple(args, "s#", &secret_ptr, &secret_len)) {
182+
if (!PyArg_ParseTuple(args, "y#", &secret_ptr, &secret_len)) {
183183
return PyErr_AwsLastError();
184184
}
185185

@@ -202,7 +202,7 @@ PyObject *aws_py_hmac_update(PyObject *self, PyObject *args) {
202202
const char *to_hmac_ptr;
203203
Py_ssize_t to_hmac_len;
204204

205-
if (!PyArg_ParseTuple(args, "Os#", &hmac_capsule, &to_hmac_ptr, &to_hmac_len)) {
205+
if (!PyArg_ParseTuple(args, "Oy#", &hmac_capsule, &to_hmac_ptr, &to_hmac_len)) {
206206
return PyErr_AwsLastError();
207207
}
208208

@@ -273,7 +273,7 @@ PyObject *aws_py_rsa_private_key_from_pem_data(PyObject *self, PyObject *args) {
273273
(void)self;
274274

275275
struct aws_byte_cursor pem_data_cur;
276-
if (!PyArg_ParseTuple(args, "s#", &pem_data_cur.ptr, &pem_data_cur.len)) {
276+
if (!PyArg_ParseTuple(args, "y#", &pem_data_cur.ptr, &pem_data_cur.len)) {
277277
return NULL;
278278
}
279279

@@ -323,7 +323,7 @@ PyObject *aws_py_rsa_public_key_from_pem_data(PyObject *self, PyObject *args) {
323323
(void)self;
324324

325325
struct aws_byte_cursor pem_data_cur;
326-
if (!PyArg_ParseTuple(args, "s#", &pem_data_cur.ptr, &pem_data_cur.len)) {
326+
if (!PyArg_ParseTuple(args, "y#", &pem_data_cur.ptr, &pem_data_cur.len)) {
327327
return NULL;
328328
}
329329

@@ -425,7 +425,7 @@ PyObject *aws_py_rsa_encrypt(PyObject *self, PyObject *args) {
425425
PyObject *rsa_capsule = NULL;
426426
int encrypt_algo = 0;
427427
struct aws_byte_cursor plaintext_cur;
428-
if (!PyArg_ParseTuple(args, "Ois#", &rsa_capsule, &encrypt_algo, &plaintext_cur.ptr, &plaintext_cur.len)) {
428+
if (!PyArg_ParseTuple(args, "Oiy#", &rsa_capsule, &encrypt_algo, &plaintext_cur.ptr, &plaintext_cur.len)) {
429429
return NULL;
430430
}
431431

@@ -793,6 +793,7 @@ PyObject *aws_py_ec_encode_signature(PyObject *self, PyObject *args) {
793793
return NULL;
794794
}
795795

796+
/* Note: PyBytes_Check does not null check, hence explicit null check before. */
796797
if (!PyBytes_Check(r_bytes) || !PyBytes_Check(s_bytes)) {
797798
PyErr_SetString(PyExc_TypeError, "r and s must be bytes");
798799
Py_DECREF(r_bytes);
@@ -836,7 +837,7 @@ PyObject *aws_py_ec_decode_signature(PyObject *self, PyObject *args) {
836837
(void)self;
837838

838839
struct aws_byte_cursor signature_cur;
839-
if (!PyArg_ParseTuple(args, "s#", &signature_cur.ptr, &signature_cur.len)) {
840+
if (!PyArg_ParseTuple(args, "y#", &signature_cur.ptr, &signature_cur.len)) {
840841
return NULL;
841842
}
842843

@@ -857,3 +858,35 @@ PyObject *aws_py_ec_decode_signature(PyObject *self, PyObject *args) {
857858

858859
return result;
859860
}
861+
862+
PyObject *aws_py_ec_get_public_coords(PyObject *self, PyObject *args) {
863+
(void)self;
864+
865+
struct aws_allocator *allocator = aws_py_get_allocator();
866+
PyObject *ec_capsule = NULL;
867+
struct aws_byte_cursor digest_cur;
868+
if (!PyArg_ParseTuple(args, "O", &ec_capsule)) {
869+
return NULL;
870+
}
871+
872+
struct aws_ecc_key_pair *ec = PyCapsule_GetPointer(ec_capsule, s_capsule_name_ec);
873+
if (ec == NULL) {
874+
return NULL;
875+
}
876+
877+
struct aws_byte_cursor x_cur = {0};
878+
struct aws_byte_cursor y_cur = {0};
879+
if (aws_ecc_key_pair_get_public_key(ec, &x_cur, &y_cur)) {
880+
return PyErr_AwsLastError();
881+
}
882+
883+
PyObject *result = PyTuple_New(2);
884+
if (!result) {
885+
return NULL;
886+
}
887+
888+
PyTuple_SetItem(result, 0, PyBytes_FromStringAndSize((char *)x_cur.ptr, x_cur.len));
889+
PyTuple_SetItem(result, 1, PyBytes_FromStringAndSize((char *)y_cur.ptr, y_cur.len));
890+
891+
return result;
892+
}

source/module.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ static PyMethodDef s_module_methods[] = {
830830
AWS_PY_METHOD_DEF(ec_verify, METH_VARARGS),
831831
AWS_PY_METHOD_DEF(ec_encode_signature, METH_VARARGS),
832832
AWS_PY_METHOD_DEF(ec_decode_signature, METH_VARARGS),
833+
AWS_PY_METHOD_DEF(ec_get_public_coords, METH_VARARGS),
833834

834835
/* Checksum primitives */
835836
AWS_PY_METHOD_DEF(checksums_crc32, METH_VARARGS),

test/test_crypto.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,21 @@ def test_ec_asn1_signing_roundtrip(self):
367367
ec = EC.new_key_from_der_data(base64.b64decode(EC_PRIVATE_KEY_SEC1_BASE64))
368368
signature = ec.sign(digest)
369369

370+
(x, y) = ec.get_public_coords();
371+
372+
expected_x = bytes([0xbf, 0x61, 0x63, 0x46, 0x93, 0x2d, 0x00, 0x33,
373+
0x19, 0xe3, 0x3a, 0x19, 0xc6, 0xc8, 0x55, 0xf5,
374+
0xc8, 0x44, 0x91, 0xe9, 0x9b, 0x83, 0x36, 0x67,
375+
0x5d, 0x25, 0x0d, 0x7b, 0xe0, 0xc0, 0xf1, 0xd2])
376+
377+
expected_y = bytes([0xaa, 0x5c, 0xdf, 0xfb, 0xa9, 0x37, 0x19, 0x8d,
378+
0x82, 0x47, 0x28, 0x88, 0xbe, 0x46, 0x7f, 0x3c,
379+
0xcd, 0x41, 0xaa, 0x08, 0x9a, 0x37, 0x0d, 0x61,
380+
0x7f, 0x5f, 0xeb, 0x9f, 0x55, 0xf7, 0x54, 0xda])
381+
382+
self.assertEqual(x, expected_x)
383+
self.assertEqual(y, expected_y)
384+
370385
(r, s) = EC.decode_der_signature(signature)
371386
self.assertEqual(signature, EC.encode_raw_signature(ECRawSignature(r=r, s=s)))
372387
print(base64.b64encode(signature))

0 commit comments

Comments
 (0)