AWS: Public Key Signing (RSA)In digital signing, we use our private key to sign for a message, and then the proof of signing is done with our public key. This happens for a Bitcoin transaction, and where we take the private key from our wallet and then sign for a transaction. The public key is then used to prove that the user signing the transaction. While Bitcoin uses ECDSA, we can also use RSA signing. A common method is RSASSA_PSS_SHA_256 () Generating the signing key pairWith digital signing we often use RSA. With this, Alices uses her private key to encrypt the message. This is passed to Bob and who takes the signature and Bob public key, and then decryts to determine the message. If the message decrypted is the same of the original message, the signature is valid: Creating an RSA key pairInitially, in AWS, we create a new customer-managed key: We then select a public key (asymmetric) and one which can sign and verify: In this case, we are using the RSA method. Next, we create an alias for the key. Next, we define the administrative permissions: And for key permissions: Finally, we have our key created: Signing a message with the private keyWe can first create a file (1.txt): With this, we will use the “aws kms sign” command. $ aws kms sign --key-id alias/MyRSAKey --message fileb://1.txt --signing-algorithm RSASSA_PSS_SHA_256 --query Signature --output text > 1.out This will produce a Base64 output for the signature: cat 1.out hKCXYApMCkBgpKyfBwPMvJMzCFLYjW4ojeOGwk9/jeREZegZMiTMtk9jmm0SdoWfpbJMm8dX/7Rkf4Dbrc2HqJDBRbu8SE4ANFl3BB71zjZfbK629aLYKI+ilpSdx6erIVyrAUIT5+gMyrOGrvuc9PGlhjIvn9VpvXqvZr7qZd9dVq3ZH6sWN6wPEFbs7b5zMqpDlDvieNlO7l7G6JfYNR5tsDAqlQOwULCXSuO76P4k8OToaXGwIc2nPgC6d9Z+zYx0ASrUTpqqusaJgMCXtxGZ3yKk0npLY9gsR4Vb+BjBA/JmX+/0Rl56RLYsZUUfJ/Cp4+ExQXLcbrcy0BXe/Q== In order to check the signature, we need to convert this format into binary: $ base64 -i 1.out -d > 1.sig If we list the signature file (1.sig), we can see it is in a binary form: $ cat 1.sig ` L `̼R؍n(ODe2$̶OcmvLWdۭ͇EHN4Yw6_l(ǧ!\B ʳ2/izfe]V7Vs2C;xN^5m0*PJ$iq!ͧ>w~͌t*NƉ"zKc,G[f_F^zD,eE'1Arn We can now verify the signature using the message (1.txt), the public key and the signature file (1.sig): aws kms verify --key-id alias/MyRSAKey --message fileb://1.txt --signature fileb://1.sig --signing-algorithm RSASSA_PSS_SHA_256 { "KeyId": "arn:aws:kms:us-east-1:960372818084:key/cc278275-bc00-4b31-9374-43d759aeed56", "SignatureValid": true, "SigningAlgorithm": "RSASSA_PSS_SHA_256" } And you can see that the signature has proved to be valid. If we change the file: And then try again, and we will get an exception: $ aws kms verify --key-id alias/MyPublicKeyForSigning --message fileb://2.txt --signature fileb://1.sig --signing-algorithm ECDSA_SHA_256 An error occurred (KMSInvalidSignatureException) when calling the Verify operation: Configuration with PythonWith Boto3, we can then convert the CLI implementation into Python. For this we use the sign() and verify() methods in boto3, and then use the SigningAlgorithm='RSASSA_PSS_SHA_256'. We use a ECC key pair, and which is "cc278275-bc00-4b31-9374-43d759aeed56": import base64 import binascii import boto3 AWS_REGION = 'us-east-1' def enable_kms_key(key_ID): try: response = kms_client.enable_key(KeyId=key_ID) except ClientError: print('KMS Key not working') raise else: return response def sign(msg, alias): try: sig = kms_client.sign(KeyId=alias,SigningAlgorithm='RSASSA_PSS_SHA_256',Message=bytes(msg, encoding='utf8'), ) except ClientError: print('Problem with encryption.') raise else: return base64.b64encode(sig["Signature"]) def verify(msg, ciphertext, alias): try: plain_text = kms_client.verify(KeyId=alias,SigningAlgorithm='RSASSA_PSS_SHA_256',Message=bytes(msg, encoding='utf8'),Signature=bytes(base64.b64decode(ciphertext))) except ClientError: print('Problem with decryption.') raise else: return plain_text['SignatureValid'] kms_client = boto3.client("kms", region_name=AWS_REGION) KEY_ID = 'cc278275-bc00-4b31-9374-43d759aeed56' kms = enable_kms_key(KEY_ID) print(f'Public Key KMS ID {KEY_ID} ') msg='Hello' print(f"Plaintext: {msg}") sig=sign(msg,KEY_ID) print(f"Signature {sig}") val=verify(msg,sig,KEY_ID) print(f"Verified: {val}") A sample run is: Public Key KMS ID cc278275-bc00-4b31-9374-43d759aeed56 Plaintext: Hello Signature b'twMKy7H9OazTPF0Y+XOQG1DCkNOKNpgc0zD2SzjShFt7B3YMeUomUkq72U6mI1yllfpDW5tDJz83dZ3+VNIlBbM8uL4s3xTF7h1KtC8Fv/3gjiFvWMOirUssL37Cyukc7ei5djq0yPIpBScRfvLHj7fySS3fwsDRZ2fLcT7xlYE/bxA/goXcSQoarU2HmFi5lcWv9G3iSACgPa0jV73eqsFucrwSfMAPI9h5CR4574ojo4cYjsjH8V/1pdlwayHQpus/i4e3VcKUGXmdgnP7sttYfqqr18cPUU3i0RJzsakM8K+IBdQ13ayWoUcHoemqSURg8iPpuRGOwmGiLEqY+g==' Verified: True ConclusionsDigital signing allows us to verify the creator of a message, and where the private key is used to sign the message, and then proven with the associated public key. |