def test_aesgcm_missing_iv_on_decrypt():
    encrypter = AES_GCMEncrypter(bit_length=192)
    enc_msg = encrypter.encrypt(b'Murder must advertise.',
                                b'Dorothy L. Sayers')
    ctx, tag = split_ctx_and_tag(enc_msg)
    with pytest.raises(ValueError):
        encrypter.decrypt(ctx, tag=tag)
def test_aesgcm_bit_length():
    encrypter = AES_GCMEncrypter(bit_length=192)
    enc_msg = encrypter.encrypt(b'Murder must advertise.',
                                b'Dorothy L. Sayers')
    ctx, tag = split_ctx_and_tag(enc_msg)
    _msg = encrypter.decrypt(ctx, iv=b'Dorothy L. Sayers', tag=tag)
    assert _msg == b'Murder must advertise.'
Esempio n. 3
0
def sign_enc_payload(load, timestamp=0, sign_key=None, enc_key=None, sign_alg="SHA256"):
    """

    :param load: The basic information in the payload
    :param timestamp: A timestamp (seconds since epoch)
    :param sign_key: A :py:class:`cryptojwt.jwk.hmac.SYMKey` instance
    :param enc_key: A :py:class:`cryptojwt.jwk.hmac.SYMKey` instance
    :param sign_alg: Which signing algorithm to use
    :return: Signed and/or encrypted payload
    """

    # Just sign, sign and encrypt or just encrypt

    if timestamp:
        timestamp = str(timestamp)
    else:
        timestamp = str(int(time.time()))

    bytes_load = load.encode("utf-8")
    bytes_timestamp = timestamp.encode("utf-8")

    if sign_key:
        signer = HMACSigner(algorithm=sign_alg)
        mac = signer.sign(bytes_load + bytes_timestamp, sign_key.key)
    else:
        mac = b""

    if enc_key:
        if len(enc_key.key) not in [16, 24, 32]:
            raise ValueError("Wrong size of enc_key")

        encrypter = AES_GCMEncrypter(key=enc_key.key)
        iv = os.urandom(12)
        if mac:
            msg = lv_pack(load, timestamp, base64.b64encode(mac).decode("utf-8"))
        else:
            msg = lv_pack(load, timestamp)

        enc_msg = encrypter.encrypt(msg.encode("utf-8"), iv)
        ctx, tag = split_ctx_and_tag(enc_msg)

        cookie_payload = [
            bytes_timestamp,
            base64.b64encode(iv),
            base64.b64encode(ctx),
            base64.b64encode(tag),
        ]
    else:
        cookie_payload = [bytes_timestamp, bytes_load, base64.b64encode(mac)]

    return (b"|".join(cookie_payload)).decode("utf-8")
Esempio n. 4
0
def make_cookie(name,
                load,
                seed,
                expire=0,
                domain="",
                path="",
                timestamp="",
                enc_key=None,
                secure=True,
                http_only=True,
                same_site=""):
    """
    Create and return a cookie

    The cookie is secured against tampering.

    If you only provide a `seed`, a HMAC gets added to the cookies value
    and this is checked, when the cookie is parsed again.

    If you provide both `seed` and `enc_key`, the cookie gets protected
    by using AEAD encryption. This provides both a MAC over the whole cookie
    and encrypts the `load` in a single step.

    The `seed` and `enc_key` parameters should be byte strings of at least
    16 bytes length each. Those are used as cryptographic keys.

    :param name: Cookie name
    :type name: text
    :param load: Cookie load
    :type load: text
    :param seed: A seed key for the HMAC function
    :type seed: byte string
    :param expire: Number of minutes before this cookie goes stale
    :type expire: int
    :param domain: The domain of the cookie
    :param path: The path specification for the cookie
    :param timestamp: A time stamp
    :type timestamp: text
    :param enc_key: The key to use for cookie encryption.
    :type enc_key: byte string
    :param secure: A secure cookie is only sent to the server with an encrypted request over the
    HTTPS protocol.
    :type secure: boolean
    :param http_only: HttpOnly cookies are inaccessible to JavaScript's Document.cookie API
    :type http_only: boolean
    :param same_site: Whether SameSite (None,Strict or Lax) should be added to the cookie
    :type same_site: byte string
    :return: A tuple to be added to headers
    """
    cookie = SimpleCookie()
    if not timestamp:
        timestamp = str(int(time.time()))

    bytes_load = as_bytes(load)
    bytes_timestamp = timestamp.encode("utf-8")

    if enc_key:
        # Make sure the key is 256-bit long, for AES-128-SIV
        #
        # This should go away once we push the keysize requirements up
        # to the top level APIs.
        key = _make_hashed_key((enc_key, seed))

        #key = AESGCM.generate_key(bit_length=128)
        aesgcm = AESGCM(key)
        iv = os.urandom(12)

        # timestamp does not need to be encrypted, just MAC'ed,
        # so we add it to 'Associated Data' only.
        ct = split_ctx_and_tag(aesgcm.encrypt(iv, bytes_load, bytes_timestamp))

        ciphertext, tag = ct
        cookie_payload = [
            bytes_timestamp,
            base64.b64encode(iv),
            base64.b64encode(ciphertext),
            base64.b64encode(tag)
        ]
    else:
        cookie_payload = [
            bytes_load, bytes_timestamp,
            cookie_signature(seed, load, timestamp).encode('utf-8')
        ]

    cookie[name] = (b"|".join(cookie_payload)).decode('utf-8')

    # Necessary if Python version < 3.8
    if sys.version_info[:2] <= (3, 8):
        cookie[name]._reserved[str("samesite")] = str("SameSite")

    if path:
        cookie[name]["path"] = path
    if domain:
        cookie[name]["domain"] = domain
    if expire:
        cookie[name]["expires"] = _expiration(expire,
                                              "%a, %d-%b-%Y %H:%M:%S GMT")
    if secure:
        cookie[name]["Secure"] = secure
    if http_only:
        cookie[name]["httponly"] = http_only
    if same_site:
        cookie[name]["SameSite"] = same_site

    return tuple(cookie.output().split(": ", 1))
def test_jwe_09_a1():
    # RSAES OAEP and AES GCM
    msg = b"The true sign of intelligence is not knowledge but imagination."

    # A.1.1
    header = b'{"alg":"RSA-OAEP","enc":"A256GCM"}'
    b64_header = b64e(header)

    # A.1.2
    assert b64_header == b"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ"

    # A.1.3
    cek = intarr2bytes([
        177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154, 212,
        246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122, 234, 64,
        252
    ])

    # A.1.4 Key Encryption
    # enc_key = [
    #     56, 163, 154, 192, 58, 53, 222, 4, 105, 218, 136, 218, 29, 94, 203,
    #     22, 150, 92, 129, 94, 211, 232, 53, 89, 41, 60, 138, 56, 196, 216,
    #     82, 98, 168, 76, 37, 73, 70, 7, 36, 8, 191, 100, 136, 196, 244, 220,
    #     145, 158, 138, 155, 4, 117, 141, 230, 199, 247, 173, 45, 182, 214,
    #     74, 177, 107, 211, 153, 11, 205, 196, 171, 226, 162, 128, 171, 182,
    #     13, 237, 239, 99, 193, 4, 91, 219, 121, 223, 107, 167, 61, 119, 228,
    #     173, 156, 137, 134, 200, 80, 219, 74, 253, 56, 185, 91, 177, 34, 158,
    #     89, 154, 205, 96, 55, 18, 138, 43, 96, 218, 215, 128, 124, 75, 138,
    #     243, 85, 25, 109, 117, 140, 26, 155, 249, 67, 167, 149, 231, 100, 6,
    #     41, 65, 214, 251, 232, 87, 72, 40, 182, 149, 154, 168, 31, 193, 126,
    #     215, 89, 28, 111, 219, 125, 182, 139, 235, 195, 197, 23, 234, 55, 58,
    #     63, 180, 68, 202, 206, 149, 75, 205, 248, 176, 67, 39, 178, 60, 98,
    #     193, 32, 238, 122, 96, 158, 222, 57, 183, 111, 210, 55, 188, 215,
    #     206, 180, 166, 150, 166, 106, 250, 55, 229, 72, 40, 69, 214, 216,
    #     104, 23, 40, 135, 212, 28, 127, 41, 80, 175, 174, 168, 115, 171, 197,
    #     89, 116, 92, 103, 246, 83, 216, 182, 176, 84, 37, 147, 35, 45, 219,
    #     172, 99, 226, 233, 73, 37, 124, 42, 72, 49, 242, 35, 127, 184, 134,
    #     117, 114, 135, 206]

    b64_ejek = b'ApfOLCaDbqs_JXPYy2I937v_xmrzj' \
               b'-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUXBtbtuGJ_A2Xe6AEhrlzCOw'

    iv = intarr2bytes([227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219])

    aadp = b64_header + b'.' + b64_ejek

    gcm = AES_GCMEncrypter(key=cek)
    ctxt, tag = split_ctx_and_tag(gcm.encrypt(msg, iv, aadp))

    _va = to_intarr(ctxt)
    assert _va == [
        229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39, 122, 233,
        96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111, 104,
        50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82, 242, 32, 123, 143,
        168, 226, 73, 216, 176, 144, 138, 247, 106, 60, 16, 205, 160, 109, 64,
        63, 192
    ]

    assert bytes2intarr(tag) == [
        130, 17, 32, 198, 120, 167, 144, 113, 0, 50, 158, 49, 102, 208, 118,
        152
    ]

    # tag = long2hexseq(tag)
    # iv = long2hexseq(iv)
    res = b".".join([b64_header, b64_ejek, b64e(iv), b64e(ctxt), b64e(tag)])

    # print(res.split(b'.'))
    expected = b'.'.join([
        b'eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ',
        b'ApfOLCaDbqs_JXPYy2I937v_xmrzj'
        b'-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUXBtbtuGJ_A2Xe6AEhrlzCOw',
        b'48V1_ALb6US04U3b',
        b'5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A',
        b'ghEgxninkHEAMp4xZtB2mA'
    ])

    assert res == expected
Esempio n. 6
0
def make_cookie(name, load, seed, domain="", path="", timestamp="",
                enc_key=None, max_age=0):
    """
    Create and return a cookie

    The cookie is secured against tampering.

    If you only provide a `seed`, a HMAC gets added to the cookies value
    and this is checked, when the cookie is parsed again.

    If you provide both `seed` and `enc_key`, the cookie gets protected
    by using AEAD encryption. This provides both a MAC over the whole cookie
    and encrypts the `load` in a single step.

    The `seed` and `enc_key` parameters should be byte strings of at least
    16 bytes length each. Those are used as cryptographic keys.

    :param name: Cookie name
    :type name: text
    :param load: Cookie load
    :type load: text
    :param seed: A seed key for the HMAC function
    :type seed: byte string
    :param domain: The domain of the cookie
    :param path: The path specification for the cookie
    :param timestamp: A time stamp
    :type timestamp: text
    :param enc_key: The key to use for cookie encryption.
    :type enc_key: byte string
    :param max_age: The time in seconds for when a cookie will be deleted
    :type max_age: int
    :return: A SimpleCookie instance
    """
    cookie = SimpleCookie()
    if not timestamp:
        timestamp = str(int(time.time()))

    bytes_load = load.encode("utf-8")
    bytes_timestamp = timestamp.encode("utf-8")

    if enc_key:
        # Make sure the key is 256-bit long, for AES-128-SIV
        #
        # This should go away once we push the keysize requirements up
        # to the top level APIs.
        key = _make_hashed_key((enc_key, seed))

        # key = AESGCM.generate_key(bit_length=128)
        aesgcm = AESGCM(key)
        iv = os.urandom(12)

        # timestamp does not need to be encrypted, just MAC'ed,
        # so we add it to 'Associated Data' only.
        ct = split_ctx_and_tag(aesgcm.encrypt(iv, bytes_load, bytes_timestamp))

        ciphertext, tag = ct
        cookie_payload = [bytes_timestamp,
                          base64.b64encode(iv),
                          base64.b64encode(ciphertext),
                          base64.b64encode(tag)]
    else:
        cookie_payload = [
            bytes_load, bytes_timestamp,
            cookie_signature(seed, load, timestamp).encode('utf-8')]

    cookie[name] = (b"|".join(cookie_payload)).decode('utf-8')
    if path:
        cookie[name]["path"] = path
    if domain:
        cookie[name]["domain"] = domain

    if max_age:
        cookie[name]["expires"] = in_a_while(seconds=max_age)

    return cookie
Esempio n. 7
0
 def _decrypt_sid(self, enc_msg):
     _msg = b64d(as_bytes(enc_msg))
     encrypter = AES_GCMEncrypter(key=as_bytes(self.server_get("endpoint_context").symkey))
     ctx, tag = split_ctx_and_tag(_msg)
     return as_unicode(encrypter.decrypt(as_bytes(ctx), iv=self.iv, tag=as_bytes(tag)))