Repository: getmoto/moto

Issue:
Not raising exception as encrypting empty string with mock_kms
Hi,

I used `mock_kms` to mock out a KMS service during unit test. Everything works fine until I deployed my code to AWS and run it. It seems that an empty string can be encrypted with moto_kms, but fails with the real KMS service.

- The moto version: 1.3.13
- Python: 3.7.4

```python
>>> from moto import mock_kms                                                                                                                  
>>> mock_kms = mock_kms()
>>> mock_kms.start()
>>> import boto3
>>> client_kms = boto3.client('kms', region_name='ap-northeast-1')                                                                             
>>> client_kms.encrypt(KeyId='kms-id', Plaintext='')                                                                                            
{'CiphertextBlob': b'', 'KeyId': 'key_id', 'ResponseMetadata': {'HTTPStatusCode': 200, 'HTTPHeaders': {'server': 'amazon.com'}, 'RetryAttempts': 0}}
>>> 
```

```python
>>> import boto3
>>> client_kms = boto3.client('kms', region_name='ap-northeast-1')
>>> client_kms.encrypt(KeyId='<my-kms-id>', Plaintext='')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/yuecen/myworks/dosomething/venv/lib/python3.7/site-packages/botocore/client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/Users/yuecen/myworks/dosomething/venv/lib/python3.7/site-packages/botocore/client.py", line 661, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the Encrypt operation: 1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1
```

moto is an awesome library!  Thank you.

yuecen



Discussion:
Thanks; going to set this as a feature request for us to add the validation here.
Looks like I did not fix this in #2397 :(

I would re-target this to: All KMS APIs need to correctly validate input values.

Key IDs are correctly validated now per #2420, and some of the other values are too, but not all.

I'll try to grab some time to look at this issue this week.

@spulec Feel free to @ me on any KMS-related issues. :)
@mattsb42-aws awesome, appreciate it!

Given your role, I'm happy to give you commit access or anything else that would be helpful. Let me know.

Resolving patch:
diff --git a/moto/kms/utils.py b/moto/kms/utils.py
--- a/moto/kms/utils.py
+++ b/moto/kms/utils.py
@@ -11,6 +11,7 @@
     InvalidCiphertextException,
     AccessDeniedException,
     NotFoundException,
+    ValidationException,
 )
 
 
@@ -102,6 +103,11 @@ def encrypt(master_keys, key_id, plaintext, encryption_context):
             )
         )
 
+    if plaintext == b"":
+        raise ValidationException(
+            "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1"
+        )
+
     iv = os.urandom(IV_LEN)
     aad = _serialize_encryption_context(encryption_context=encryption_context)
 


Test patch:
diff --git a/tests/test_kms/test_kms_boto3.py b/tests/test_kms/test_kms_boto3.py
--- a/tests/test_kms/test_kms_boto3.py
+++ b/tests/test_kms/test_kms_boto3.py
@@ -40,6 +40,19 @@ def test_create_key_without_description():
     metadata.should.have.key("Description").equal("")
 
 
+@mock_kms
+def test_create_key_with_empty_content():
+    client_kms = boto3.client("kms", region_name="ap-northeast-1")
+    metadata = client_kms.create_key(Policy="my policy")["KeyMetadata"]
+    with pytest.raises(ClientError) as exc:
+        client_kms.encrypt(KeyId=metadata["KeyId"], Plaintext="")
+    err = exc.value.response["Error"]
+    err["Code"].should.equal("ValidationException")
+    err["Message"].should.equal(
+        "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1"
+    )
+
+
 @mock_kms
 def test_create_key():
     conn = boto3.client("kms", region_name="us-east-1")