This library implements HTTP Message Signatures. The underlying crypto is provided by PyCryptodomex.
Pypi Page: https://pypi.org/project/httpsigpy/
Usage:
from httpsig import *
To sign an HTTP message, first it has to be parsed into its message components:
msg = event['body'].encode('utf-8')
components = parse_components(msg)
This provides a data structure with each possible message component indexed by its name, identifier, and value.
To create the signature input, pass in the parsed components structure as well as a list of components to sign, with the signature parameters:
siginput = generate_input(
components,
( # covered components list
{ 'id': "@method" },
{ 'id': "@authority" },
{ 'id': "@path" },
{ 'id': "content-digest" },
{ 'id': "content-length" },
{ 'id': "content-type" }
),
{
'created': 1618884473,
'keyid': 'test-key-rsa-pss'
}
)
base = siginput['signatureInput']
sigparams = siginput['signatureParams']
This outputs a base
string that can be passed to the signer.
key = RSA.import_key(PKCS8.unwrap(PEM.decode(rsaTestKeyPssPrivate)[0])[1])
h = SHA512.new(base.encode('utf-8'))
signer = pss.new(key, mask_func=mgf512, salt_bytes=64)
signed = http_sfv.Item(signer.sign(h))
To verify an HTTP message, first it has to be parsed into its message components:
msg = event['body'].encode('utf-8')
components = parse_components(msg)
This provides a data structure with each possible message component indexed by its name, identifier, and value.
To create the signature input, pass in the parsed components structure as well as a list of components to sign, and the signature parameters.
siginput = generate_input(
components,
( # covered components list
{ 'id': "@method" },
{ 'id': "@authority" },
{ 'id': "@path" },
{ 'id': "content-digest" },
{ 'id': "content-length" },
{ 'id': "content-type" }
),
{
'created': 1618884473,
'keyid': 'test-key-rsa-pss'
}
)
This can be passed to the verifier function:
h = SHA512.new(base.encode('utf-8'))
pubKey = RSA.import_key(rsaTestKeyPssPublic)
verifier = pss.new(pubKey, mask_func=mgf512, salt_bytes=64)
try:
verified = verifier.verify(h, signed.value)
print('> YES!')
except (ValueError, TypeError):
print('> NO!')