We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Several KMS operations are broken on Windows in 1.3.8
The change from https://github.com/spulec/moto/pull/2073 breaks several KMS operations on Windows because the `%s` format specifier is platform specific and not supported in python.

This can be easily fixed by changing the timestamp generation to use:
> `(datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()`

An example stack trace of a test that throws is included below.

```
tests\test_kms.py:33: in _create_kms_key
    key = kms_client.create_key(Policy="Policy", KeyUsage='ENCRYPT_DECRYPT')
wenv\lib\site-packages\botocore\client.py:357: in _api_call
    return self._make_api_call(operation_name, kwargs)
wenv\lib\site-packages\botocore\client.py:648: in _make_api_call
    operation_model, request_dict, request_context)
wenv\lib\site-packages\botocore\client.py:667: in _make_request
    return self._endpoint.make_request(operation_model, request_dict)
wenv\lib\site-packages\botocore\endpoint.py:102: in make_request
    return self._send_request(request_dict, operation_model)
wenv\lib\site-packages\botocore\endpoint.py:137: in _send_request
    success_response, exception):
wenv\lib\site-packages\botocore\endpoint.py:231: in _needs_retry
    caught_exception=caught_exception, request_dict=request_dict)
wenv\lib\site-packages\botocore\hooks.py:356: in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
wenv\lib\site-packages\botocore\hooks.py:228: in emit
    return self._emit(event_name, kwargs)
wenv\lib\site-packages\botocore\hooks.py:211: in _emit
    response = handler(**kwargs)
wenv\lib\site-packages\botocore\retryhandler.py:183: in __call__
    if self._checker(attempts, response, caught_exception):
wenv\lib\site-packages\botocore\retryhandler.py:251: in __call__
    caught_exception)
wenv\lib\site-packages\botocore\retryhandler.py:269: in _should_retry
    return self._checker(attempt_number, response, caught_exception)
wenv\lib\site-packages\botocore\retryhandler.py:317: in __call__
    caught_exception)
wenv\lib\site-packages\botocore\retryhandler.py:223: in __call__
    attempt_number, caught_exception)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <botocore.retryhandler.ExceptionRaiser object at 0x0000000011A51A58>
attempt_number = 1, caught_exception = ValueError('Invalid format string',)

    def _check_caught_exception(self, attempt_number, caught_exception):
        # This is implementation specific, but this class is useful by
        # coordinating with the MaxAttemptsDecorator.
        # The MaxAttemptsDecorator has a list of exceptions it should catch
        # and retry, but something needs to come along and actually raise the
        # caught_exception.  That's what this class is being used for.  If
        # the MaxAttemptsDecorator is not interested in retrying the exception
        # then this exception just propogates out past the retry code.
        print(dir(caught_exception))
>       raise caught_exception
E       ValueError: Invalid format string
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `moto/kms/models.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import os
4 import boto.kms
5 from moto.core import BaseBackend, BaseModel
6 from moto.core.utils import iso_8601_datetime_without_milliseconds
7 from .utils import generate_key_id
8 from collections import defaultdict
9 from datetime import datetime, timedelta
10 
11 
12 class Key(BaseModel):
13 
14     def __init__(self, policy, key_usage, description, region):
15         self.id = generate_key_id()
16         self.policy = policy
17         self.key_usage = key_usage
18         self.key_state = "Enabled"
19         self.description = description
20         self.enabled = True
21         self.region = region
22         self.account_id = "0123456789012"
23         self.key_rotation_status = False
24         self.deletion_date = None
25         self.tags = {}
26 
27     @property
28     def physical_resource_id(self):
29         return self.id
30 
31     @property
32     def arn(self):
33         return "arn:aws:kms:{0}:{1}:key/{2}".format(self.region, self.account_id, self.id)
34 
35     def to_dict(self):
36         key_dict = {
37             "KeyMetadata": {
38                 "AWSAccountId": self.account_id,
39                 "Arn": self.arn,
40                 "CreationDate": datetime.strftime(datetime.utcnow(), "%s"),
41                 "Description": self.description,
42                 "Enabled": self.enabled,
43                 "KeyId": self.id,
44                 "KeyUsage": self.key_usage,
45                 "KeyState": self.key_state,
46             }
47         }
48         if self.key_state == 'PendingDeletion':
49             key_dict['KeyMetadata']['DeletionDate'] = iso_8601_datetime_without_milliseconds(self.deletion_date)
50         return key_dict
51 
52     def delete(self, region_name):
53         kms_backends[region_name].delete_key(self.id)
54 
55     @classmethod
56     def create_from_cloudformation_json(self, resource_name, cloudformation_json, region_name):
57         kms_backend = kms_backends[region_name]
58         properties = cloudformation_json['Properties']
59 
60         key = kms_backend.create_key(
61             policy=properties['KeyPolicy'],
62             key_usage='ENCRYPT_DECRYPT',
63             description=properties['Description'],
64             region=region_name,
65         )
66         key.key_rotation_status = properties['EnableKeyRotation']
67         key.enabled = properties['Enabled']
68         return key
69 
70     def get_cfn_attribute(self, attribute_name):
71         from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
72         if attribute_name == 'Arn':
73             return self.arn
74         raise UnformattedGetAttTemplateException()
75 
76 
77 class KmsBackend(BaseBackend):
78 
79     def __init__(self):
80         self.keys = {}
81         self.key_to_aliases = defaultdict(set)
82 
83     def create_key(self, policy, key_usage, description, region):
84         key = Key(policy, key_usage, description, region)
85         self.keys[key.id] = key
86         return key
87 
88     def update_key_description(self, key_id, description):
89         key = self.keys[self.get_key_id(key_id)]
90         key.description = description
91 
92     def tag_resource(self, key_id, tags):
93         key = self.keys[self.get_key_id(key_id)]
94         key.tags = tags
95 
96     def list_resource_tags(self, key_id):
97         key = self.keys[self.get_key_id(key_id)]
98         return key.tags
99 
100     def delete_key(self, key_id):
101         if key_id in self.keys:
102             if key_id in self.key_to_aliases:
103                 self.key_to_aliases.pop(key_id)
104 
105             return self.keys.pop(key_id)
106 
107     def describe_key(self, key_id):
108         # allow the different methods (alias, ARN :key/, keyId, ARN alias) to
109         # describe key not just KeyId
110         key_id = self.get_key_id(key_id)
111         if r'alias/' in str(key_id).lower():
112             key_id = self.get_key_id_from_alias(key_id.split('alias/')[1])
113         return self.keys[self.get_key_id(key_id)]
114 
115     def list_keys(self):
116         return self.keys.values()
117 
118     def get_key_id(self, key_id):
119         # Allow use of ARN as well as pure KeyId
120         return str(key_id).split(r':key/')[1] if r':key/' in str(key_id).lower() else key_id
121 
122     def alias_exists(self, alias_name):
123         for aliases in self.key_to_aliases.values():
124             if alias_name in aliases:
125                 return True
126 
127         return False
128 
129     def add_alias(self, target_key_id, alias_name):
130         self.key_to_aliases[target_key_id].add(alias_name)
131 
132     def delete_alias(self, alias_name):
133         """Delete the alias."""
134         for aliases in self.key_to_aliases.values():
135             if alias_name in aliases:
136                 aliases.remove(alias_name)
137 
138     def get_all_aliases(self):
139         return self.key_to_aliases
140 
141     def get_key_id_from_alias(self, alias_name):
142         for key_id, aliases in dict(self.key_to_aliases).items():
143             if alias_name in ",".join(aliases):
144                 return key_id
145         return None
146 
147     def enable_key_rotation(self, key_id):
148         self.keys[self.get_key_id(key_id)].key_rotation_status = True
149 
150     def disable_key_rotation(self, key_id):
151         self.keys[self.get_key_id(key_id)].key_rotation_status = False
152 
153     def get_key_rotation_status(self, key_id):
154         return self.keys[self.get_key_id(key_id)].key_rotation_status
155 
156     def put_key_policy(self, key_id, policy):
157         self.keys[self.get_key_id(key_id)].policy = policy
158 
159     def get_key_policy(self, key_id):
160         return self.keys[self.get_key_id(key_id)].policy
161 
162     def disable_key(self, key_id):
163         self.keys[key_id].enabled = False
164         self.keys[key_id].key_state = 'Disabled'
165 
166     def enable_key(self, key_id):
167         self.keys[key_id].enabled = True
168         self.keys[key_id].key_state = 'Enabled'
169 
170     def cancel_key_deletion(self, key_id):
171         self.keys[key_id].key_state = 'Disabled'
172         self.keys[key_id].deletion_date = None
173 
174     def schedule_key_deletion(self, key_id, pending_window_in_days):
175         if 7 <= pending_window_in_days <= 30:
176             self.keys[key_id].enabled = False
177             self.keys[key_id].key_state = 'PendingDeletion'
178             self.keys[key_id].deletion_date = datetime.now() + timedelta(days=pending_window_in_days)
179             return iso_8601_datetime_without_milliseconds(self.keys[key_id].deletion_date)
180 
181     def generate_data_key(self, key_id, encryption_context, number_of_bytes, key_spec, grant_tokens):
182         key = self.keys[self.get_key_id(key_id)]
183 
184         if key_spec:
185             if key_spec == 'AES_128':
186                 bytes = 16
187             else:
188                 bytes = 32
189         else:
190             bytes = number_of_bytes
191 
192         plaintext = os.urandom(bytes)
193 
194         return plaintext, key.arn
195 
196 
197 kms_backends = {}
198 for region in boto.kms.regions():
199     kms_backends[region.name] = KmsBackend()
200
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/moto/kms/models.py b/moto/kms/models.py
--- a/moto/kms/models.py
+++ b/moto/kms/models.py
@@ -3,7 +3,7 @@
 import os
 import boto.kms
 from moto.core import BaseBackend, BaseModel
-from moto.core.utils import iso_8601_datetime_without_milliseconds
+from moto.core.utils import iso_8601_datetime_without_milliseconds, unix_time
 from .utils import generate_key_id
 from collections import defaultdict
 from datetime import datetime, timedelta
@@ -37,7 +37,7 @@
             "KeyMetadata": {
                 "AWSAccountId": self.account_id,
                 "Arn": self.arn,
-                "CreationDate": datetime.strftime(datetime.utcnow(), "%s"),
+                "CreationDate": "%d" % unix_time(),
                 "Description": self.description,
                 "Enabled": self.enabled,
                 "KeyId": self.id,

{"golden_diff": "diff --git a/moto/kms/models.py b/moto/kms/models.py\n--- a/moto/kms/models.py\n+++ b/moto/kms/models.py\n@@ -3,7 +3,7 @@\n import os\n import boto.kms\n from moto.core import BaseBackend, BaseModel\n-from moto.core.utils import iso_8601_datetime_without_milliseconds\n+from moto.core.utils import iso_8601_datetime_without_milliseconds, unix_time\n from .utils import generate_key_id\n from collections import defaultdict\n from datetime import datetime, timedelta\n@@ -37,7 +37,7 @@\n             \"KeyMetadata\": {\n                 \"AWSAccountId\": self.account_id,\n                 \"Arn\": self.arn,\n-                \"CreationDate\": datetime.strftime(datetime.utcnow(), \"%s\"),\n+                \"CreationDate\": \"%d\" % unix_time(),\n                 \"Description\": self.description,\n                 \"Enabled\": self.enabled,\n                 \"KeyId\": self.id,\n", "issue": "Several KMS operations are broken on Windows in 1.3.8\nThe change from https://github.com/spulec/moto/pull/2073 breaks several KMS operations on Windows because the `%s` format specifier is platform specific and not supported in python.\r\n\r\nThis can be easily fixed by changing the timestamp generation to use:\r\n> `(datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()`\r\n\r\nAn example stack trace of a test that throws is included below.\r\n\r\n```\r\ntests\\test_kms.py:33: in _create_kms_key\r\n    key = kms_client.create_key(Policy=\"Policy\", KeyUsage='ENCRYPT_DECRYPT')\r\nwenv\\lib\\site-packages\\botocore\\client.py:357: in _api_call\r\n    return self._make_api_call(operation_name, kwargs)\r\nwenv\\lib\\site-packages\\botocore\\client.py:648: in _make_api_call\r\n    operation_model, request_dict, request_context)\r\nwenv\\lib\\site-packages\\botocore\\client.py:667: in _make_request\r\n    return self._endpoint.make_request(operation_model, request_dict)\r\nwenv\\lib\\site-packages\\botocore\\endpoint.py:102: in make_request\r\n    return self._send_request(request_dict, operation_model)\r\nwenv\\lib\\site-packages\\botocore\\endpoint.py:137: in _send_request\r\n    success_response, exception):\r\nwenv\\lib\\site-packages\\botocore\\endpoint.py:231: in _needs_retry\r\n    caught_exception=caught_exception, request_dict=request_dict)\r\nwenv\\lib\\site-packages\\botocore\\hooks.py:356: in emit\r\n    return self._emitter.emit(aliased_event_name, **kwargs)\r\nwenv\\lib\\site-packages\\botocore\\hooks.py:228: in emit\r\n    return self._emit(event_name, kwargs)\r\nwenv\\lib\\site-packages\\botocore\\hooks.py:211: in _emit\r\n    response = handler(**kwargs)\r\nwenv\\lib\\site-packages\\botocore\\retryhandler.py:183: in __call__\r\n    if self._checker(attempts, response, caught_exception):\r\nwenv\\lib\\site-packages\\botocore\\retryhandler.py:251: in __call__\r\n    caught_exception)\r\nwenv\\lib\\site-packages\\botocore\\retryhandler.py:269: in _should_retry\r\n    return self._checker(attempt_number, response, caught_exception)\r\nwenv\\lib\\site-packages\\botocore\\retryhandler.py:317: in __call__\r\n    caught_exception)\r\nwenv\\lib\\site-packages\\botocore\\retryhandler.py:223: in __call__\r\n    attempt_number, caught_exception)\r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\r\n\r\nself = <botocore.retryhandler.ExceptionRaiser object at 0x0000000011A51A58>\r\nattempt_number = 1, caught_exception = ValueError('Invalid format string',)\r\n\r\n    def _check_caught_exception(self, attempt_number, caught_exception):\r\n        # This is implementation specific, but this class is useful by\r\n        # coordinating with the MaxAttemptsDecorator.\r\n        # The MaxAttemptsDecorator has a list of exceptions it should catch\r\n        # and retry, but something needs to come along and actually raise the\r\n        # caught_exception.  That's what this class is being used for.  If\r\n        # the MaxAttemptsDecorator is not interested in retrying the exception\r\n        # then this exception just propogates out past the retry code.\r\n        print(dir(caught_exception))\r\n>       raise caught_exception\r\nE       ValueError: Invalid format string\r\n```\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nimport boto.kms\nfrom moto.core import BaseBackend, BaseModel\nfrom moto.core.utils import iso_8601_datetime_without_milliseconds\nfrom .utils import generate_key_id\nfrom collections import defaultdict\nfrom datetime import datetime, timedelta\n\n\nclass Key(BaseModel):\n\n    def __init__(self, policy, key_usage, description, region):\n        self.id = generate_key_id()\n        self.policy = policy\n        self.key_usage = key_usage\n        self.key_state = \"Enabled\"\n        self.description = description\n        self.enabled = True\n        self.region = region\n        self.account_id = \"0123456789012\"\n        self.key_rotation_status = False\n        self.deletion_date = None\n        self.tags = {}\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @property\n    def arn(self):\n        return \"arn:aws:kms:{0}:{1}:key/{2}\".format(self.region, self.account_id, self.id)\n\n    def to_dict(self):\n        key_dict = {\n            \"KeyMetadata\": {\n                \"AWSAccountId\": self.account_id,\n                \"Arn\": self.arn,\n                \"CreationDate\": datetime.strftime(datetime.utcnow(), \"%s\"),\n                \"Description\": self.description,\n                \"Enabled\": self.enabled,\n                \"KeyId\": self.id,\n                \"KeyUsage\": self.key_usage,\n                \"KeyState\": self.key_state,\n            }\n        }\n        if self.key_state == 'PendingDeletion':\n            key_dict['KeyMetadata']['DeletionDate'] = iso_8601_datetime_without_milliseconds(self.deletion_date)\n        return key_dict\n\n    def delete(self, region_name):\n        kms_backends[region_name].delete_key(self.id)\n\n    @classmethod\n    def create_from_cloudformation_json(self, resource_name, cloudformation_json, region_name):\n        kms_backend = kms_backends[region_name]\n        properties = cloudformation_json['Properties']\n\n        key = kms_backend.create_key(\n            policy=properties['KeyPolicy'],\n            key_usage='ENCRYPT_DECRYPT',\n            description=properties['Description'],\n            region=region_name,\n        )\n        key.key_rotation_status = properties['EnableKeyRotation']\n        key.enabled = properties['Enabled']\n        return key\n\n    def get_cfn_attribute(self, attribute_name):\n        from moto.cloudformation.exceptions import UnformattedGetAttTemplateException\n        if attribute_name == 'Arn':\n            return self.arn\n        raise UnformattedGetAttTemplateException()\n\n\nclass KmsBackend(BaseBackend):\n\n    def __init__(self):\n        self.keys = {}\n        self.key_to_aliases = defaultdict(set)\n\n    def create_key(self, policy, key_usage, description, region):\n        key = Key(policy, key_usage, description, region)\n        self.keys[key.id] = key\n        return key\n\n    def update_key_description(self, key_id, description):\n        key = self.keys[self.get_key_id(key_id)]\n        key.description = description\n\n    def tag_resource(self, key_id, tags):\n        key = self.keys[self.get_key_id(key_id)]\n        key.tags = tags\n\n    def list_resource_tags(self, key_id):\n        key = self.keys[self.get_key_id(key_id)]\n        return key.tags\n\n    def delete_key(self, key_id):\n        if key_id in self.keys:\n            if key_id in self.key_to_aliases:\n                self.key_to_aliases.pop(key_id)\n\n            return self.keys.pop(key_id)\n\n    def describe_key(self, key_id):\n        # allow the different methods (alias, ARN :key/, keyId, ARN alias) to\n        # describe key not just KeyId\n        key_id = self.get_key_id(key_id)\n        if r'alias/' in str(key_id).lower():\n            key_id = self.get_key_id_from_alias(key_id.split('alias/')[1])\n        return self.keys[self.get_key_id(key_id)]\n\n    def list_keys(self):\n        return self.keys.values()\n\n    def get_key_id(self, key_id):\n        # Allow use of ARN as well as pure KeyId\n        return str(key_id).split(r':key/')[1] if r':key/' in str(key_id).lower() else key_id\n\n    def alias_exists(self, alias_name):\n        for aliases in self.key_to_aliases.values():\n            if alias_name in aliases:\n                return True\n\n        return False\n\n    def add_alias(self, target_key_id, alias_name):\n        self.key_to_aliases[target_key_id].add(alias_name)\n\n    def delete_alias(self, alias_name):\n        \"\"\"Delete the alias.\"\"\"\n        for aliases in self.key_to_aliases.values():\n            if alias_name in aliases:\n                aliases.remove(alias_name)\n\n    def get_all_aliases(self):\n        return self.key_to_aliases\n\n    def get_key_id_from_alias(self, alias_name):\n        for key_id, aliases in dict(self.key_to_aliases).items():\n            if alias_name in \",\".join(aliases):\n                return key_id\n        return None\n\n    def enable_key_rotation(self, key_id):\n        self.keys[self.get_key_id(key_id)].key_rotation_status = True\n\n    def disable_key_rotation(self, key_id):\n        self.keys[self.get_key_id(key_id)].key_rotation_status = False\n\n    def get_key_rotation_status(self, key_id):\n        return self.keys[self.get_key_id(key_id)].key_rotation_status\n\n    def put_key_policy(self, key_id, policy):\n        self.keys[self.get_key_id(key_id)].policy = policy\n\n    def get_key_policy(self, key_id):\n        return self.keys[self.get_key_id(key_id)].policy\n\n    def disable_key(self, key_id):\n        self.keys[key_id].enabled = False\n        self.keys[key_id].key_state = 'Disabled'\n\n    def enable_key(self, key_id):\n        self.keys[key_id].enabled = True\n        self.keys[key_id].key_state = 'Enabled'\n\n    def cancel_key_deletion(self, key_id):\n        self.keys[key_id].key_state = 'Disabled'\n        self.keys[key_id].deletion_date = None\n\n    def schedule_key_deletion(self, key_id, pending_window_in_days):\n        if 7 <= pending_window_in_days <= 30:\n            self.keys[key_id].enabled = False\n            self.keys[key_id].key_state = 'PendingDeletion'\n            self.keys[key_id].deletion_date = datetime.now() + timedelta(days=pending_window_in_days)\n            return iso_8601_datetime_without_milliseconds(self.keys[key_id].deletion_date)\n\n    def generate_data_key(self, key_id, encryption_context, number_of_bytes, key_spec, grant_tokens):\n        key = self.keys[self.get_key_id(key_id)]\n\n        if key_spec:\n            if key_spec == 'AES_128':\n                bytes = 16\n            else:\n                bytes = 32\n        else:\n            bytes = number_of_bytes\n\n        plaintext = os.urandom(bytes)\n\n        return plaintext, key.arn\n\n\nkms_backends = {}\nfor region in boto.kms.regions():\n    kms_backends[region.name] = KmsBackend()\n", "path": "moto/kms/models.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nimport boto.kms\nfrom moto.core import BaseBackend, BaseModel\nfrom moto.core.utils import iso_8601_datetime_without_milliseconds, unix_time\nfrom .utils import generate_key_id\nfrom collections import defaultdict\nfrom datetime import datetime, timedelta\n\n\nclass Key(BaseModel):\n\n    def __init__(self, policy, key_usage, description, region):\n        self.id = generate_key_id()\n        self.policy = policy\n        self.key_usage = key_usage\n        self.key_state = \"Enabled\"\n        self.description = description\n        self.enabled = True\n        self.region = region\n        self.account_id = \"0123456789012\"\n        self.key_rotation_status = False\n        self.deletion_date = None\n        self.tags = {}\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @property\n    def arn(self):\n        return \"arn:aws:kms:{0}:{1}:key/{2}\".format(self.region, self.account_id, self.id)\n\n    def to_dict(self):\n        key_dict = {\n            \"KeyMetadata\": {\n                \"AWSAccountId\": self.account_id,\n                \"Arn\": self.arn,\n                \"CreationDate\": \"%d\" % unix_time(),\n                \"Description\": self.description,\n                \"Enabled\": self.enabled,\n                \"KeyId\": self.id,\n                \"KeyUsage\": self.key_usage,\n                \"KeyState\": self.key_state,\n            }\n        }\n        if self.key_state == 'PendingDeletion':\n            key_dict['KeyMetadata']['DeletionDate'] = iso_8601_datetime_without_milliseconds(self.deletion_date)\n        return key_dict\n\n    def delete(self, region_name):\n        kms_backends[region_name].delete_key(self.id)\n\n    @classmethod\n    def create_from_cloudformation_json(self, resource_name, cloudformation_json, region_name):\n        kms_backend = kms_backends[region_name]\n        properties = cloudformation_json['Properties']\n\n        key = kms_backend.create_key(\n            policy=properties['KeyPolicy'],\n            key_usage='ENCRYPT_DECRYPT',\n            description=properties['Description'],\n            region=region_name,\n        )\n        key.key_rotation_status = properties['EnableKeyRotation']\n        key.enabled = properties['Enabled']\n        return key\n\n    def get_cfn_attribute(self, attribute_name):\n        from moto.cloudformation.exceptions import UnformattedGetAttTemplateException\n        if attribute_name == 'Arn':\n            return self.arn\n        raise UnformattedGetAttTemplateException()\n\n\nclass KmsBackend(BaseBackend):\n\n    def __init__(self):\n        self.keys = {}\n        self.key_to_aliases = defaultdict(set)\n\n    def create_key(self, policy, key_usage, description, region):\n        key = Key(policy, key_usage, description, region)\n        self.keys[key.id] = key\n        return key\n\n    def update_key_description(self, key_id, description):\n        key = self.keys[self.get_key_id(key_id)]\n        key.description = description\n\n    def tag_resource(self, key_id, tags):\n        key = self.keys[self.get_key_id(key_id)]\n        key.tags = tags\n\n    def list_resource_tags(self, key_id):\n        key = self.keys[self.get_key_id(key_id)]\n        return key.tags\n\n    def delete_key(self, key_id):\n        if key_id in self.keys:\n            if key_id in self.key_to_aliases:\n                self.key_to_aliases.pop(key_id)\n\n            return self.keys.pop(key_id)\n\n    def describe_key(self, key_id):\n        # allow the different methods (alias, ARN :key/, keyId, ARN alias) to\n        # describe key not just KeyId\n        key_id = self.get_key_id(key_id)\n        if r'alias/' in str(key_id).lower():\n            key_id = self.get_key_id_from_alias(key_id.split('alias/')[1])\n        return self.keys[self.get_key_id(key_id)]\n\n    def list_keys(self):\n        return self.keys.values()\n\n    def get_key_id(self, key_id):\n        # Allow use of ARN as well as pure KeyId\n        return str(key_id).split(r':key/')[1] if r':key/' in str(key_id).lower() else key_id\n\n    def alias_exists(self, alias_name):\n        for aliases in self.key_to_aliases.values():\n            if alias_name in aliases:\n                return True\n\n        return False\n\n    def add_alias(self, target_key_id, alias_name):\n        self.key_to_aliases[target_key_id].add(alias_name)\n\n    def delete_alias(self, alias_name):\n        \"\"\"Delete the alias.\"\"\"\n        for aliases in self.key_to_aliases.values():\n            if alias_name in aliases:\n                aliases.remove(alias_name)\n\n    def get_all_aliases(self):\n        return self.key_to_aliases\n\n    def get_key_id_from_alias(self, alias_name):\n        for key_id, aliases in dict(self.key_to_aliases).items():\n            if alias_name in \",\".join(aliases):\n                return key_id\n        return None\n\n    def enable_key_rotation(self, key_id):\n        self.keys[self.get_key_id(key_id)].key_rotation_status = True\n\n    def disable_key_rotation(self, key_id):\n        self.keys[self.get_key_id(key_id)].key_rotation_status = False\n\n    def get_key_rotation_status(self, key_id):\n        return self.keys[self.get_key_id(key_id)].key_rotation_status\n\n    def put_key_policy(self, key_id, policy):\n        self.keys[self.get_key_id(key_id)].policy = policy\n\n    def get_key_policy(self, key_id):\n        return self.keys[self.get_key_id(key_id)].policy\n\n    def disable_key(self, key_id):\n        self.keys[key_id].enabled = False\n        self.keys[key_id].key_state = 'Disabled'\n\n    def enable_key(self, key_id):\n        self.keys[key_id].enabled = True\n        self.keys[key_id].key_state = 'Enabled'\n\n    def cancel_key_deletion(self, key_id):\n        self.keys[key_id].key_state = 'Disabled'\n        self.keys[key_id].deletion_date = None\n\n    def schedule_key_deletion(self, key_id, pending_window_in_days):\n        if 7 <= pending_window_in_days <= 30:\n            self.keys[key_id].enabled = False\n            self.keys[key_id].key_state = 'PendingDeletion'\n            self.keys[key_id].deletion_date = datetime.now() + timedelta(days=pending_window_in_days)\n            return iso_8601_datetime_without_milliseconds(self.keys[key_id].deletion_date)\n\n    def generate_data_key(self, key_id, encryption_context, number_of_bytes, key_spec, grant_tokens):\n        key = self.keys[self.get_key_id(key_id)]\n\n        if key_spec:\n            if key_spec == 'AES_128':\n                bytes = 16\n            else:\n                bytes = 32\n        else:\n            bytes = number_of_bytes\n\n        plaintext = os.urandom(bytes)\n\n        return plaintext, key.arn\n\n\nkms_backends = {}\nfor region in boto.kms.regions():\n    kms_backends[region.name] = KmsBackend()\n", "path": "moto/kms/models.py"}]}