blob: b4f3f53dfb4d4fbbe1f2df4110d37d765d4b8049 [file] [log] [blame]
"""
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