# crypto.py
#
# Part of kepi, an ActivityPub daemon.
# Copyright (c) 2018-2019 Marnanel Thurman.
# Licensed under the GNU Public License v2.

"""
Various crypto routines, used for signing messages and
verifying other people's signatures.
"""

from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from struct import pack
import base64
import hashlib

def base64url_encode(data):
    """
    base64-encodes its input, using the modified URL-safe
    alphabet given in RFC 4648.
    """
    b = base64.b64encode(s=data,
            altchars=b'-_')
    return str(b, encoding='ASCII')

def bignum_to_bytes(bignum):

    temp = bignum
    result = []

    while temp!=0:
        result.append(temp & 0xFF)
        temp >>= 8

    result.reverse()
    return bytes(result)

class Key(object):
    """
    An RSA public/private key pair, which can produce
    a magic-envelope signature for itself.

    I was going to subclass the RSA key object,
    but it's hidden away and has an underscore prefix,
    so I guess the developers thought that was a bad idea.
    So I'm wrapping it, instead.
    """

    def __init__(self):
        self._rsa_key = RSA.generate(1024)

    def private_as_pem(self):
        return str(self._rsa_key.exportKey('PEM'),
                encoding='ASCII')

    def public_as_pem(self):
        return str(self._rsa_key.publickey().exportKey('PEM'),
                encoding='ASCII')

    def modulus(self):
        return self._rsa_key.n
    
    def public_exponent(self):
        return self._rsa_key.e

    def private_exponent(self):
        return self._rsa_key.d

    def magic_envelope(self):
        return 'RSA.{0}.{1}'.format(
                base64url_encode(
                    bignum_to_bytes(
                        self._rsa_key.n)),
                base64url_encode(
                    bignum_to_bytes(
                        self._rsa_key.e)),
                )
