1# Copyright (c) 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the 5# "Software"), to deal in the Software without restriction, including 6# without limitation the rights to use, copy, modify, merge, publish, dis- 7# tribute, sublicense, and/or sell copies of the Software, and to permit 8# persons to whom the Software is furnished to do so, subject to the fol- 9# lowing conditions: 10# 11# The above copyright notice and this permission notice shall be included 12# in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21# 22 23import boto 24from boto.compat import json 25from boto.connection import AWSQueryConnection 26from boto.regioninfo import RegionInfo 27from boto.exception import JSONResponseError 28from boto.kms import exceptions 29from boto.compat import six 30import base64 31 32 33class KMSConnection(AWSQueryConnection): 34 """ 35 AWS Key Management Service 36 AWS Key Management Service (KMS) is an encryption and key 37 management web service. This guide describes the KMS actions that 38 you can call programmatically. For general information about KMS, 39 see (need an address here). For the KMS developer guide, see (need 40 address here). 41 42 AWS provides SDKs that consist of libraries and sample code for 43 various programming languages and platforms (Java, Ruby, .Net, 44 iOS, Android, etc.). The SDKs provide a convenient way to create 45 programmatic access to KMS and AWS. For example, the SDKs take 46 care of tasks such as signing requests (see below), managing 47 errors, and retrying requests automatically. For more information 48 about the AWS SDKs, including how to download and install them, 49 see `Tools for Amazon Web Services`_. 50 51 We recommend that you use the AWS SDKs to make programmatic API 52 calls to KMS. However, you can also use the KMS Query API to make 53 to make direct calls to the KMS web service. 54 55 **Signing Requests** 56 57 Requests must be signed by using an access key ID and a secret 58 access key. We strongly recommend that you do not use your AWS 59 account access key ID and secret key for everyday work with KMS. 60 Instead, use the access key ID and secret access key for an IAM 61 user, or you can use the AWS Security Token Service to generate 62 temporary security credentials that you can use to sign requests. 63 64 All KMS operations require `Signature Version 4`_. 65 66 **Recording API Requests** 67 68 KMS supports AWS CloudTrail, a service that records AWS API calls 69 and related events for your AWS account and delivers them to an 70 Amazon S3 bucket that you specify. By using the information 71 collected by CloudTrail, you can determine what requests were made 72 to KMS, who made the request, when it was made, and so on. To 73 learn more about CloudTrail, including how to turn it on and find 74 your log files, see the `AWS CloudTrail User Guide`_ 75 76 **Additional Resources** 77 78 For more information about credentials and request signing, see 79 the following: 80 81 82 + `AWS Security Credentials`_. This topic provides general 83 information about the types of credentials used for accessing AWS. 84 + `AWS Security Token Service`_. This guide describes how to 85 create and use temporary security credentials. 86 + `Signing AWS API Requests`_. This set of topics walks you 87 through the process of signing a request using an access key ID 88 and a secret access key. 89 """ 90 APIVersion = "2014-11-01" 91 DefaultRegionName = "us-east-1" 92 DefaultRegionEndpoint = "kms.us-east-1.amazonaws.com" 93 ServiceName = "KMS" 94 TargetPrefix = "TrentService" 95 ResponseError = JSONResponseError 96 97 _faults = { 98 "InvalidGrantTokenException": exceptions.InvalidGrantTokenException, 99 "DisabledException": exceptions.DisabledException, 100 "LimitExceededException": exceptions.LimitExceededException, 101 "DependencyTimeoutException": exceptions.DependencyTimeoutException, 102 "InvalidMarkerException": exceptions.InvalidMarkerException, 103 "AlreadyExistsException": exceptions.AlreadyExistsException, 104 "InvalidCiphertextException": exceptions.InvalidCiphertextException, 105 "KeyUnavailableException": exceptions.KeyUnavailableException, 106 "InvalidAliasNameException": exceptions.InvalidAliasNameException, 107 "UnsupportedOperationException": exceptions.UnsupportedOperationException, 108 "InvalidArnException": exceptions.InvalidArnException, 109 "KMSInternalException": exceptions.KMSInternalException, 110 "InvalidKeyUsageException": exceptions.InvalidKeyUsageException, 111 "MalformedPolicyDocumentException": exceptions.MalformedPolicyDocumentException, 112 "NotFoundException": exceptions.NotFoundException, 113 } 114 115 116 def __init__(self, **kwargs): 117 region = kwargs.pop('region', None) 118 if not region: 119 region = RegionInfo(self, self.DefaultRegionName, 120 self.DefaultRegionEndpoint) 121 122 if 'host' not in kwargs or kwargs['host'] is None: 123 kwargs['host'] = region.endpoint 124 125 super(KMSConnection, self).__init__(**kwargs) 126 self.region = region 127 128 def _required_auth_capability(self): 129 return ['hmac-v4'] 130 131 def create_alias(self, alias_name, target_key_id): 132 """ 133 Creates a display name for a customer master key. An alias can 134 be used to identify a key and should be unique. The console 135 enforces a one-to-one mapping between the alias and a key. An 136 alias name can contain only alphanumeric characters, forward 137 slashes (/), underscores (_), and dashes (-). An alias must 138 start with the word "alias" followed by a forward slash 139 (alias/). An alias that begins with "aws" after the forward 140 slash (alias/aws...) is reserved by Amazon Web Services (AWS). 141 142 :type alias_name: string 143 :param alias_name: String that contains the display name. Aliases that 144 begin with AWS are reserved. 145 146 :type target_key_id: string 147 :param target_key_id: An identifier of the key for which you are 148 creating the alias. This value cannot be another alias. 149 150 """ 151 params = { 152 'AliasName': alias_name, 153 'TargetKeyId': target_key_id, 154 } 155 return self.make_request(action='CreateAlias', 156 body=json.dumps(params)) 157 158 def create_grant(self, key_id, grantee_principal, 159 retiring_principal=None, operations=None, 160 constraints=None, grant_tokens=None): 161 """ 162 Adds a grant to a key to specify who can access the key and 163 under what conditions. Grants are alternate permission 164 mechanisms to key policies. If absent, access to the key is 165 evaluated based on IAM policies attached to the user. By 166 default, grants do not expire. Grants can be listed, retired, 167 or revoked as indicated by the following APIs. Typically, when 168 you are finished using a grant, you retire it. When you want 169 to end a grant immediately, revoke it. For more information 170 about grants, see `Grants`_. 171 172 #. ListGrants 173 #. RetireGrant 174 #. RevokeGrant 175 176 :type key_id: string 177 :param key_id: A unique key identifier for a customer master key. This 178 value can be a globally unique identifier, an ARN, or an alias. 179 180 :type grantee_principal: string 181 :param grantee_principal: Principal given permission by the grant to 182 use the key identified by the `keyId` parameter. 183 184 :type retiring_principal: string 185 :param retiring_principal: Principal given permission to retire the 186 grant. For more information, see RetireGrant. 187 188 :type operations: list 189 :param operations: List of operations permitted by the grant. This can 190 be any combination of one or more of the following values: 191 192 #. Decrypt 193 #. Encrypt 194 #. GenerateDataKey 195 #. GenerateDataKeyWithoutPlaintext 196 #. ReEncryptFrom 197 #. ReEncryptTo 198 #. CreateGrant 199 200 :type constraints: dict 201 :param constraints: Specifies the conditions under which the actions 202 specified by the `Operations` parameter are allowed. 203 204 :type grant_tokens: list 205 :param grant_tokens: List of grant tokens. 206 207 """ 208 params = { 209 'KeyId': key_id, 210 'GranteePrincipal': grantee_principal, 211 } 212 if retiring_principal is not None: 213 params['RetiringPrincipal'] = retiring_principal 214 if operations is not None: 215 params['Operations'] = operations 216 if constraints is not None: 217 params['Constraints'] = constraints 218 if grant_tokens is not None: 219 params['GrantTokens'] = grant_tokens 220 return self.make_request(action='CreateGrant', 221 body=json.dumps(params)) 222 223 def create_key(self, policy=None, description=None, key_usage=None): 224 """ 225 Creates a customer master key. Customer master keys can be 226 used to encrypt small amounts of data (less than 4K) directly, 227 but they are most commonly used to encrypt or envelope data 228 keys that are then used to encrypt customer data. For more 229 information about data keys, see GenerateDataKey and 230 GenerateDataKeyWithoutPlaintext. 231 232 :type policy: string 233 :param policy: Policy to be attached to the key. This is required and 234 delegates back to the account. The key is the root of trust. 235 236 :type description: string 237 :param description: Description of the key. We recommend that you 238 choose a description that helps your customer decide whether the 239 key is appropriate for a task. 240 241 :type key_usage: string 242 :param key_usage: Specifies the intended use of the key. Currently this 243 defaults to ENCRYPT/DECRYPT, and only symmetric encryption and 244 decryption are supported. 245 246 """ 247 params = {} 248 if policy is not None: 249 params['Policy'] = policy 250 if description is not None: 251 params['Description'] = description 252 if key_usage is not None: 253 params['KeyUsage'] = key_usage 254 return self.make_request(action='CreateKey', 255 body=json.dumps(params)) 256 257 def decrypt(self, ciphertext_blob, encryption_context=None, 258 grant_tokens=None): 259 """ 260 Decrypts ciphertext. Ciphertext is plaintext that has been 261 previously encrypted by using the Encrypt function. 262 263 :type ciphertext_blob: blob 264 :param ciphertext_blob: Ciphertext including metadata. 265 266 :type encryption_context: map 267 :param encryption_context: The encryption context. If this was 268 specified in the Encrypt function, it must be specified here or the 269 decryption operation will fail. For more information, see 270 `Encryption Context`_. 271 272 :type grant_tokens: list 273 :param grant_tokens: A list of grant tokens that represent grants which 274 can be used to provide long term permissions to perform decryption. 275 276 """ 277 if not isinstance(ciphertext_blob, six.binary_type): 278 raise TypeError( 279 "Value of argument ``ciphertext_blob`` " 280 "must be of type %s." % six.binary_type) 281 ciphertext_blob = base64.b64encode(ciphertext_blob) 282 params = {'CiphertextBlob': ciphertext_blob, } 283 if encryption_context is not None: 284 params['EncryptionContext'] = encryption_context 285 if grant_tokens is not None: 286 params['GrantTokens'] = grant_tokens 287 response = self.make_request(action='Decrypt', 288 body=json.dumps(params)) 289 if response.get('Plaintext') is not None: 290 response['Plaintext'] = base64.b64decode( 291 response['Plaintext'].encode('utf-8')) 292 return response 293 294 def delete_alias(self, alias_name): 295 """ 296 Deletes the specified alias. 297 298 :type alias_name: string 299 :param alias_name: The alias to be deleted. 300 301 """ 302 params = {'AliasName': alias_name, } 303 return self.make_request(action='DeleteAlias', 304 body=json.dumps(params)) 305 306 def describe_key(self, key_id): 307 """ 308 Provides detailed information about the specified customer 309 master key. 310 311 :type key_id: string 312 :param key_id: Unique identifier of the customer master key to be 313 described. This can be an ARN, an alias, or a globally unique 314 identifier. 315 316 """ 317 params = {'KeyId': key_id, } 318 return self.make_request(action='DescribeKey', 319 body=json.dumps(params)) 320 321 def disable_key(self, key_id): 322 """ 323 Marks a key as disabled, thereby preventing its use. 324 325 :type key_id: string 326 :param key_id: Unique identifier of the customer master key to be 327 disabled. This can be an ARN, an alias, or a globally unique 328 identifier. 329 330 """ 331 params = {'KeyId': key_id, } 332 return self.make_request(action='DisableKey', 333 body=json.dumps(params)) 334 335 def disable_key_rotation(self, key_id): 336 """ 337 Disables rotation of the specified key. 338 339 :type key_id: string 340 :param key_id: Unique identifier of the customer master key for which 341 rotation is to be disabled. This can be an ARN, an alias, or a 342 globally unique identifier. 343 344 """ 345 params = {'KeyId': key_id, } 346 return self.make_request(action='DisableKeyRotation', 347 body=json.dumps(params)) 348 349 def enable_key(self, key_id): 350 """ 351 Marks a key as enabled, thereby permitting its use. You can 352 have up to 25 enabled keys at one time. 353 354 :type key_id: string 355 :param key_id: Unique identifier of the customer master key to be 356 enabled. This can be an ARN, an alias, or a globally unique 357 identifier. 358 359 """ 360 params = {'KeyId': key_id, } 361 return self.make_request(action='EnableKey', 362 body=json.dumps(params)) 363 364 def enable_key_rotation(self, key_id): 365 """ 366 Enables rotation of the specified customer master key. 367 368 :type key_id: string 369 :param key_id: Unique identifier of the customer master key for which 370 rotation is to be enabled. This can be an ARN, an alias, or a 371 globally unique identifier. 372 373 """ 374 params = {'KeyId': key_id, } 375 return self.make_request(action='EnableKeyRotation', 376 body=json.dumps(params)) 377 378 def encrypt(self, key_id, plaintext, encryption_context=None, 379 grant_tokens=None): 380 """ 381 Encrypts plaintext into ciphertext by using a customer master 382 key. 383 384 :type key_id: string 385 :param key_id: Unique identifier of the customer master. This can be an 386 ARN, an alias, or the Key ID. 387 388 :type plaintext: blob 389 :param plaintext: Data to be encrypted. 390 391 :type encryption_context: map 392 :param encryption_context: Name:value pair that specifies the 393 encryption context to be used for authenticated encryption. For 394 more information, see `Authenticated Encryption`_. 395 396 :type grant_tokens: list 397 :param grant_tokens: A list of grant tokens that represent grants which 398 can be used to provide long term permissions to perform encryption. 399 400 """ 401 if not isinstance(plaintext, six.binary_type): 402 raise TypeError( 403 "Value of argument ``plaintext`` " 404 "must be of type %s." % six.binary_type) 405 plaintext = base64.b64encode(plaintext) 406 params = {'KeyId': key_id, 'Plaintext': plaintext, } 407 if encryption_context is not None: 408 params['EncryptionContext'] = encryption_context 409 if grant_tokens is not None: 410 params['GrantTokens'] = grant_tokens 411 response = self.make_request(action='Encrypt', 412 body=json.dumps(params)) 413 if response.get('CiphertextBlob') is not None: 414 response['CiphertextBlob'] = base64.b64decode( 415 response['CiphertextBlob'].encode('utf-8')) 416 return response 417 418 def generate_data_key(self, key_id, encryption_context=None, 419 number_of_bytes=None, key_spec=None, 420 grant_tokens=None): 421 """ 422 Generates a secure data key. Data keys are used to encrypt and 423 decrypt data. They are wrapped by customer master keys. 424 425 :type key_id: string 426 :param key_id: Unique identifier of the key. This can be an ARN, an 427 alias, or a globally unique identifier. 428 429 :type encryption_context: map 430 :param encryption_context: Name/value pair that contains additional 431 data to be authenticated during the encryption and decryption 432 processes that use the key. This value is logged by AWS CloudTrail 433 to provide context around the data encrypted by the key. 434 435 :type number_of_bytes: integer 436 :param number_of_bytes: Integer that contains the number of bytes to 437 generate. Common values are 128, 256, 512, 1024 and so on. 1024 is 438 the current limit. 439 440 :type key_spec: string 441 :param key_spec: Value that identifies the encryption algorithm and key 442 size to generate a data key for. Currently this can be AES_128 or 443 AES_256. 444 445 :type grant_tokens: list 446 :param grant_tokens: A list of grant tokens that represent grants which 447 can be used to provide long term permissions to generate a key. 448 449 """ 450 params = {'KeyId': key_id, } 451 if encryption_context is not None: 452 params['EncryptionContext'] = encryption_context 453 if number_of_bytes is not None: 454 params['NumberOfBytes'] = number_of_bytes 455 if key_spec is not None: 456 params['KeySpec'] = key_spec 457 if grant_tokens is not None: 458 params['GrantTokens'] = grant_tokens 459 response = self.make_request(action='GenerateDataKey', 460 body=json.dumps(params)) 461 if response.get('CiphertextBlob') is not None: 462 response['CiphertextBlob'] = base64.b64decode( 463 response['CiphertextBlob'].encode('utf-8')) 464 if response.get('Plaintext') is not None: 465 response['Plaintext'] = base64.b64decode( 466 response['Plaintext'].encode('utf-8')) 467 return response 468 469 def generate_data_key_without_plaintext(self, key_id, 470 encryption_context=None, 471 key_spec=None, 472 number_of_bytes=None, 473 grant_tokens=None): 474 """ 475 Returns a key wrapped by a customer master key without the 476 plaintext copy of that key. To retrieve the plaintext, see 477 GenerateDataKey. 478 479 :type key_id: string 480 :param key_id: Unique identifier of the key. This can be an ARN, an 481 alias, or a globally unique identifier. 482 483 :type encryption_context: map 484 :param encryption_context: Name:value pair that contains additional 485 data to be authenticated during the encryption and decryption 486 processes. 487 488 :type key_spec: string 489 :param key_spec: Value that identifies the encryption algorithm and key 490 size. Currently this can be AES_128 or AES_256. 491 492 :type number_of_bytes: integer 493 :param number_of_bytes: Integer that contains the number of bytes to 494 generate. Common values are 128, 256, 512, 1024 and so on. 495 496 :type grant_tokens: list 497 :param grant_tokens: A list of grant tokens that represent grants which 498 can be used to provide long term permissions to generate a key. 499 500 """ 501 params = {'KeyId': key_id, } 502 if encryption_context is not None: 503 params['EncryptionContext'] = encryption_context 504 if key_spec is not None: 505 params['KeySpec'] = key_spec 506 if number_of_bytes is not None: 507 params['NumberOfBytes'] = number_of_bytes 508 if grant_tokens is not None: 509 params['GrantTokens'] = grant_tokens 510 response = self.make_request(action='GenerateDataKeyWithoutPlaintext', 511 body=json.dumps(params)) 512 if response.get('CiphertextBlob') is not None: 513 response['CiphertextBlob'] = base64.b64decode( 514 response['CiphertextBlob'].encode('utf-8')) 515 return response 516 517 def generate_random(self, number_of_bytes=None): 518 """ 519 Generates an unpredictable byte string. 520 521 :type number_of_bytes: integer 522 :param number_of_bytes: Integer that contains the number of bytes to 523 generate. Common values are 128, 256, 512, 1024 and so on. The 524 current limit is 1024 bytes. 525 526 """ 527 params = {} 528 if number_of_bytes is not None: 529 params['NumberOfBytes'] = number_of_bytes 530 response = self.make_request(action='GenerateRandom', 531 body=json.dumps(params)) 532 if response.get('Plaintext') is not None: 533 response['Plaintext'] = base64.b64decode( 534 response['Plaintext'].encode('utf-8')) 535 return response 536 537 def get_key_policy(self, key_id, policy_name): 538 """ 539 Retrieves a policy attached to the specified key. 540 541 :type key_id: string 542 :param key_id: Unique identifier of the key. This can be an ARN, an 543 alias, or a globally unique identifier. 544 545 :type policy_name: string 546 :param policy_name: String that contains the name of the policy. 547 Currently, this must be "default". Policy names can be discovered 548 by calling ListKeyPolicies. 549 550 """ 551 params = {'KeyId': key_id, 'PolicyName': policy_name, } 552 return self.make_request(action='GetKeyPolicy', 553 body=json.dumps(params)) 554 555 def get_key_rotation_status(self, key_id): 556 """ 557 Retrieves a Boolean value that indicates whether key rotation 558 is enabled for the specified key. 559 560 :type key_id: string 561 :param key_id: Unique identifier of the key. This can be an ARN, an 562 alias, or a globally unique identifier. 563 564 """ 565 params = {'KeyId': key_id, } 566 return self.make_request(action='GetKeyRotationStatus', 567 body=json.dumps(params)) 568 569 def list_aliases(self, limit=None, marker=None): 570 """ 571 Lists all of the key aliases in the account. 572 573 :type limit: integer 574 :param limit: Specify this parameter when paginating results to 575 indicate the maximum number of aliases you want in each response. 576 If there are additional aliases beyond the maximum you specify, the 577 `Truncated` response element will be set to `true.` 578 579 :type marker: string 580 :param marker: Use this parameter when paginating results, and only in 581 a subsequent request after you've received a response where the 582 results are truncated. Set it to the value of the `NextMarker` 583 element in the response you just received. 584 585 """ 586 params = {} 587 if limit is not None: 588 params['Limit'] = limit 589 if marker is not None: 590 params['Marker'] = marker 591 return self.make_request(action='ListAliases', 592 body=json.dumps(params)) 593 594 def list_grants(self, key_id, limit=None, marker=None): 595 """ 596 List the grants for a specified key. 597 598 :type key_id: string 599 :param key_id: Unique identifier of the key. This can be an ARN, an 600 alias, or a globally unique identifier. 601 602 :type limit: integer 603 :param limit: Specify this parameter only when paginating results to 604 indicate the maximum number of grants you want listed in the 605 response. If there are additional grants beyond the maximum you 606 specify, the `Truncated` response element will be set to `true.` 607 608 :type marker: string 609 :param marker: Use this parameter only when paginating results, and 610 only in a subsequent request after you've received a response where 611 the results are truncated. Set it to the value of the `NextMarker` 612 in the response you just received. 613 614 """ 615 params = {'KeyId': key_id, } 616 if limit is not None: 617 params['Limit'] = limit 618 if marker is not None: 619 params['Marker'] = marker 620 return self.make_request(action='ListGrants', 621 body=json.dumps(params)) 622 623 def list_key_policies(self, key_id, limit=None, marker=None): 624 """ 625 Retrieves a list of policies attached to a key. 626 627 :type key_id: string 628 :param key_id: Unique identifier of the key. This can be an ARN, an 629 alias, or a globally unique identifier. 630 631 :type limit: integer 632 :param limit: Specify this parameter only when paginating results to 633 indicate the maximum number of policies you want listed in the 634 response. If there are additional policies beyond the maximum you 635 specify, the `Truncated` response element will be set to `true.` 636 637 :type marker: string 638 :param marker: Use this parameter only when paginating results, and 639 only in a subsequent request after you've received a response where 640 the results are truncated. Set it to the value of the `NextMarker` 641 in the response you just received. 642 643 """ 644 params = {'KeyId': key_id, } 645 if limit is not None: 646 params['Limit'] = limit 647 if marker is not None: 648 params['Marker'] = marker 649 return self.make_request(action='ListKeyPolicies', 650 body=json.dumps(params)) 651 652 def list_keys(self, limit=None, marker=None): 653 """ 654 Lists the customer master keys. 655 656 :type limit: integer 657 :param limit: Specify this parameter only when paginating results to 658 indicate the maximum number of keys you want listed in the 659 response. If there are additional keys beyond the maximum you 660 specify, the `Truncated` response element will be set to `true.` 661 662 :type marker: string 663 :param marker: Use this parameter only when paginating results, and 664 only in a subsequent request after you've received a response where 665 the results are truncated. Set it to the value of the `NextMarker` 666 in the response you just received. 667 668 """ 669 params = {} 670 if limit is not None: 671 params['Limit'] = limit 672 if marker is not None: 673 params['Marker'] = marker 674 return self.make_request(action='ListKeys', 675 body=json.dumps(params)) 676 677 def put_key_policy(self, key_id, policy_name, policy): 678 """ 679 Attaches a policy to the specified key. 680 681 :type key_id: string 682 :param key_id: Unique identifier of the key. This can be an ARN, an 683 alias, or a globally unique identifier. 684 685 :type policy_name: string 686 :param policy_name: Name of the policy to be attached. Currently, the 687 only supported name is "default". 688 689 :type policy: string 690 :param policy: The policy, in JSON format, to be attached to the key. 691 692 """ 693 params = { 694 'KeyId': key_id, 695 'PolicyName': policy_name, 696 'Policy': policy, 697 } 698 return self.make_request(action='PutKeyPolicy', 699 body=json.dumps(params)) 700 701 def re_encrypt(self, ciphertext_blob, destination_key_id, 702 source_encryption_context=None, 703 destination_encryption_context=None, grant_tokens=None): 704 """ 705 Encrypts data on the server side with a new customer master 706 key without exposing the plaintext of the data on the client 707 side. The data is first decrypted and then encrypted. This 708 operation can also be used to change the encryption context of 709 a ciphertext. 710 711 :type ciphertext_blob: blob 712 :param ciphertext_blob: Ciphertext of the data to re-encrypt. 713 714 :type source_encryption_context: map 715 :param source_encryption_context: Encryption context used to encrypt 716 and decrypt the data specified in the `CiphertextBlob` parameter. 717 718 :type destination_key_id: string 719 :param destination_key_id: Key identifier of the key used to re-encrypt 720 the data. 721 722 :type destination_encryption_context: map 723 :param destination_encryption_context: Encryption context to be used 724 when the data is re-encrypted. 725 726 :type grant_tokens: list 727 :param grant_tokens: Grant tokens that identify the grants that have 728 permissions for the encryption and decryption process. 729 730 """ 731 if not isinstance(ciphertext_blob, six.binary_type): 732 raise TypeError( 733 "Value of argument ``ciphertext_blob`` " 734 "must be of type %s." % six.binary_type) 735 ciphertext_blob = base64.b64encode(ciphertext_blob) 736 params = { 737 'CiphertextBlob': ciphertext_blob, 738 'DestinationKeyId': destination_key_id, 739 } 740 if source_encryption_context is not None: 741 params['SourceEncryptionContext'] = source_encryption_context 742 if destination_encryption_context is not None: 743 params['DestinationEncryptionContext'] = destination_encryption_context 744 if grant_tokens is not None: 745 params['GrantTokens'] = grant_tokens 746 response = self.make_request(action='ReEncrypt', 747 body=json.dumps(params)) 748 if response.get('CiphertextBlob') is not None: 749 response['CiphertextBlob'] = base64.b64decode( 750 response['CiphertextBlob'].encode('utf-8')) 751 return response 752 753 def retire_grant(self, grant_token): 754 """ 755 Retires a grant. You can retire a grant when you're done using 756 it to clean up. You should revoke a grant when you intend to 757 actively deny operations that depend on it. 758 759 :type grant_token: string 760 :param grant_token: Token that identifies the grant to be retired. 761 762 """ 763 params = {'GrantToken': grant_token, } 764 return self.make_request(action='RetireGrant', 765 body=json.dumps(params)) 766 767 def revoke_grant(self, key_id, grant_id): 768 """ 769 Revokes a grant. You can revoke a grant to actively deny 770 operations that depend on it. 771 772 :type key_id: string 773 :param key_id: Unique identifier of the key associated with the grant. 774 775 :type grant_id: string 776 :param grant_id: Identifier of the grant to be revoked. 777 778 """ 779 params = {'KeyId': key_id, 'GrantId': grant_id, } 780 return self.make_request(action='RevokeGrant', 781 body=json.dumps(params)) 782 783 def update_key_description(self, key_id, description): 784 """ 785 786 787 :type key_id: string 788 :param key_id: 789 790 :type description: string 791 :param description: 792 793 """ 794 params = {'KeyId': key_id, 'Description': description, } 795 return self.make_request(action='UpdateKeyDescription', 796 body=json.dumps(params)) 797 798 def make_request(self, action, body): 799 headers = { 800 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action), 801 'Host': self.region.endpoint, 802 'Content-Type': 'application/x-amz-json-1.1', 803 'Content-Length': str(len(body)), 804 } 805 http_request = self.build_base_http_request( 806 method='POST', path='/', auth_path='/', params={}, 807 headers=headers, data=body) 808 response = self._mexe(http_request, sender=None, 809 override_num_retries=10) 810 response_body = response.read().decode('utf-8') 811 boto.log.debug(response_body) 812 if response.status == 200: 813 if response_body: 814 return json.loads(response_body) 815 else: 816 json_body = json.loads(response_body) 817 fault_name = json_body.get('__type', None) 818 exception_class = self._faults.get(fault_name, self.ResponseError) 819 raise exception_class(response.status, response.reason, 820 body=json_body) 821 822