| """ |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://WWW.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| """ |
| |
| """ |
| |
| This module use cffi to access the c functions for the amcl RSA. |
| |
| """ |
| |
| from . import core_utils |
| import platform |
| |
| _ffi = core_utils._ffi |
| _ffi.cdef(""" |
| #define FFLEN_WWW @ML@ |
| #define HFLEN_WWW @HML@ |
| |
| typedef signed int sign32; |
| |
| typedef struct |
| { |
| sign32 e; |
| BIG_XXX n[FFLEN_WWW]; |
| } rsa_public_key_WWW; |
| |
| typedef struct |
| { |
| BIG_XXX p[HFLEN_WWW]; |
| BIG_XXX q[HFLEN_WWW]; |
| BIG_XXX dp[HFLEN_WWW]; |
| BIG_XXX dq[HFLEN_WWW]; |
| BIG_XXX c[HFLEN_WWW]; |
| } rsa_private_key_WWW; |
| |
| extern void FF_WWW_toOctet(octet *X, BIG_XXX *x, int n); |
| |
| extern void RSA_WWW_KEY_PAIR(csprng *R,sign32 e,rsa_private_key_WWW* PRIV,rsa_public_key_WWW* PUB,octet *P, octet* Q); |
| extern void RSA_WWW_ENCRYPT(rsa_public_key_WWW* PUB,octet *F,octet *G); |
| extern void RSA_WWW_DECRYPT(rsa_private_key_WWW* PRIV,octet *G,octet *F); |
| extern void RSA_WWW_PRIVATE_KEY_KILL(rsa_private_key_WWW *PRIV); |
| extern void RSA_WWW_fromOctet(BIG_XXX *x,octet *S); |
| |
| extern int OAEP_ENCODE(int h,octet *M,csprng *R,octet *P,octet *F); |
| extern int OAEP_DECODE(int h,octet *P,octet *F); |
| """) |
| |
| if (platform.system() == 'Windows'): |
| _libamcl_rsa_WWW = _ffi.dlopen("libamcl_rsa_WWW.dll") |
| elif (platform.system() == 'Darwin'): |
| _libamcl_rsa_WWW = _ffi.dlopen("libamcl_rsa_WWW.dylib") |
| else: |
| _libamcl_rsa_WWW = _ffi.dlopen("libamcl_rsa_WWW.so") |
| |
| # Constants |
| FFLEN = @ML@ # FF size in BIGs |
| FS = @TFF@ // 8 # FF size in bytes |
| SHA256 = 32 |
| SHA384 = 48 |
| SHA512 = 64 |
| |
| OK = 0 |
| FAIL = -1 |
| |
| |
| def generate_key_pair(rng, e, p = None, q = None): |
| """ Generate an RSA key pair |
| |
| Generate an RSA key pair with encryption exponent e |
| |
| Args:: |
| |
| rng: pointer to cryptographically secure prng |
| e: decryption exponent. Integer |
| p: Secret prime for the RSA modulus |
| q: Secret prime for the RSA modulus |
| |
| Returns:: |
| public_key: pointer to an RSA public key |
| private_key: pointer to an RSA private key |
| |
| Raises:: |
| Exception |
| """ |
| if p and q: |
| p_oct, p_oct_val = core_utils.make_octet(None, p) |
| q_oct, q_oct_val = core_utils.make_octet(None, q) |
| _ = p_oct_val, q_oct_val |
| rng = _ffi.NULL |
| else: |
| p_oct = _ffi.NULL |
| q_oct = _ffi.NULL |
| |
| public_key = _ffi.new('rsa_public_key_WWW*') |
| private_key = _ffi.new('rsa_private_key_WWW*') |
| |
| _libamcl_rsa_WWW.RSA_WWW_KEY_PAIR(rng, _ffi.cast("sign32", e), private_key, public_key, p_oct, q_oct) |
| |
| if p_oct is not _ffi.NULL: |
| core_utils.clear_octet(p_oct) |
| |
| if q_oct is not _ffi.NULL: |
| core_utils.clear_octet(q_oct) |
| |
| return public_key, private_key |
| |
| |
| def encrypt(public_key, pt): |
| """ RSA Encrypt |
| |
| Encrypt a message pt to the given public key |
| |
| Args:: |
| |
| public_key: RSA public key |
| pt: input padded message. SHA bytes |
| |
| Returns:: |
| ct: output ciphertext |
| |
| Raises:: |
| Exception |
| """ |
| pt_oct, pt_val = core_utils.make_octet(None, pt) |
| ct_oct, ct_val = core_utils.make_octet(FS) |
| _ = pt_val, ct_val |
| |
| _libamcl_rsa_WWW.RSA_WWW_ENCRYPT(public_key, pt_oct, ct_oct) |
| |
| core_utils.clear_octet(pt_oct) |
| |
| return core_utils.to_str(ct_oct) |
| |
| |
| def decrypt(private_key, ct): |
| """ RSA Decrypt |
| |
| Decrypt a ciphertext ct using the given private key |
| |
| Args:: |
| |
| private_key: RSA private key |
| ct: input ciphertext |
| |
| Returns:: |
| pt: output plaintext. SHA bytes |
| |
| Raises:: |
| Exception |
| """ |
| pt_oct, pt_val = core_utils.make_octet(FS) |
| ct_oct, ct_val = core_utils.make_octet(None, ct) |
| _ = pt_val, ct_val |
| |
| _libamcl_rsa_WWW.RSA_WWW_DECRYPT(private_key, ct_oct, pt_oct) |
| |
| pt = core_utils.to_str(pt_oct) |
| |
| # Clear memory |
| core_utils.clear_octet(pt_oct) |
| |
| return pt |
| |
| |
| def kill_private_key(private_key): |
| """ Kill RSA Private Key |
| |
| Clean secrets from an RSA private key |
| |
| Args:: |
| |
| private_key: RSA private key to kill |
| |
| Raises:: |
| Exception |
| """ |
| _libamcl_rsa_WWW.RSA_WWW_PRIVATE_KEY_KILL(private_key) |
| |
| def public_key_to_bytes(public_key): |
| """ Export public key to bytes |
| |
| Export the public key modulus as bytes. |
| The public key exponent can be accessed as an integer |
| |
| Args:: |
| |
| public_key: RSA private key to export |
| |
| Returns:: |
| |
| n: public modulus of the public key |
| |
| Raises:: |
| Exception |
| """ |
| n_oct, n_val = core_utils.make_octet(FS) |
| _ = n_val |
| |
| _libamcl_rsa_WWW.FF_WWW_toOctet(n_oct, public_key.n, FFLEN) |
| |
| return core_utils.to_str(n_oct) |
| |
| def public_key_from_bytes(n): |
| """ Import public key from bytes |
| |
| Import the public key modulus from bytes. |
| The public key exponent can be directly set as an integer |
| |
| Args:: |
| |
| n: public modulus of the public key |
| |
| Returns:: |
| |
| public_key: imported public key |
| |
| Raises:: |
| Exception |
| """ |
| n_oct, n_val = core_utils.make_octet(None, n) |
| _ = n_val |
| |
| public_key = _ffi.new('rsa_public_key_WWW*') |
| |
| _libamcl_rsa_WWW.RSA_WWW_fromOctet(public_key.n, n_oct) |
| |
| return public_key |
| |
| def oaep_encode(rng, sha, m, params=None): |
| """ Apply OAEP padding to the given message m |
| |
| OAEP padding of the message m for RSA encryption. |
| |
| Args:: |
| |
| rng: pointer to cryptograpically secure PRNG |
| sha: hash type. Supported types are SHA256, SHA384 and SHA512 |
| m: message to pad |
| params: optional parameter string for padding |
| |
| Returns:: |
| |
| pt: padded message |
| rc: 0 if the message was succesfully padded or an error code |
| |
| Raises:: |
| Exception |
| """ |
| if params is None: |
| p_oct = _ffi.NULL |
| else: |
| p_oct, p_val = core_utils.make_octet(None, params) |
| _ = p_val |
| |
| m_oct, m_val = core_utils.make_octet(None, m) |
| pt_oct, pt_val = core_utils.make_octet(FS) |
| _ = m_val, pt_val |
| |
| rc = _libamcl_rsa_WWW.OAEP_ENCODE(sha, m_oct, rng, p_oct, pt_oct) |
| if rc != 0: |
| return None, FAIL |
| |
| pt = core_utils.to_str(pt_oct) |
| |
| # Clean memory |
| core_utils.clear_octet(pt_oct) |
| core_utils.clear_octet(m_oct) |
| |
| return pt, OK |
| |
| |
| def oaep_decode(sha, pt, params=None): |
| """ Remove OAEP padding from the given plaintext pt |
| |
| OAEP unpadding of the plaintext pt to recover the message m |
| |
| Args:: |
| |
| sha: hash type. Supported types are SHA256, SHA384 and SHA512 |
| pt: plaintext from RSA decryption |
| |
| Returns:: |
| |
| m: unpadded message |
| rc: 0 if the message was succesfully unpadded or an error code |
| |
| Raises:: |
| Exception |
| """ |
| if params is None: |
| p_oct = _ffi.NULL |
| else: |
| p_oct, p_val = core_utils.make_octet(None, params) |
| _ = p_val |
| |
| pt_oct, pt_val = core_utils.make_octet(None, pt) |
| _ = pt_val |
| |
| rc = _libamcl_rsa_WWW.OAEP_DECODE(sha, p_oct, pt_oct) |
| if rc != 0: |
| return None, FAIL |
| |
| m = core_utils.to_str(pt_oct) |
| |
| # Clear memory |
| core_utils.clear_octet(pt_oct) |
| |
| return m, OK |