diff --git a/moto/kms/responses.py b/moto/kms/responses.py index aa500ca5..6a67614a 100644 --- a/moto/kms/responses.py +++ b/moto/kms/responses.py @@ -2,7 +2,9 @@ from __future__ import unicode_literals import base64 import json +import os import re + import six from moto.core.responses import BaseResponse @@ -384,6 +386,15 @@ class KmsResponse(BaseResponse): return json.dumps(result) + def generate_random(self): + number_of_bytes = self.parameters.get("NumberOfBytes") + + entropy = os.urandom(number_of_bytes) + + response_entropy = base64.b64encode(entropy).decode("utf-8") + + return json.dumps({"Plaintext": response_entropy}) + def _assert_valid_key_id(key_id): if not re.match(r'^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$', key_id, re.IGNORECASE): diff --git a/tests/test_kms/test_kms.py b/tests/test_kms/test_kms.py index 1c5aa39e..4daeaa7c 100644 --- a/tests/test_kms/test_kms.py +++ b/tests/test_kms/test_kms.py @@ -908,6 +908,21 @@ def test_re_encrypt_to_invalid_destination(): ) +@parameterized(((12,), (44,), (91,))) +@mock_kms +def test_generate_random(number_of_bytes): + client = boto3.client("kms", region_name="us-west-2") + + response = client.generate_random(NumberOfBytes=number_of_bytes) + + # Plaintext must NOT be base64-encoded + with assert_raises(Exception): + base64.b64decode(response["Plaintext"], validate=True) + + response["Plaintext"].should.be.a(bytes) + len(response["Plaintext"]).should.equal(number_of_bytes) + + @mock_kms def test_enable_key_rotation_key_not_found(): client = boto3.client("kms", region_name="us-east-1")