add escalator frame
[escalator.git] / api / escalator / common / crypt.py
1
2 # Copyright 2011 OpenStack Foundation
3 # All Rights Reserved.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 """
18 Routines for URL-safe encrypting/decrypting
19 """
20
21 import base64
22
23 from Crypto.Cipher import AES
24 from Crypto import Random
25 from Crypto.Random import random
26 # NOTE(jokke): simplified transition to py3, behaves like py2 xrange
27 from six.moves import range
28
29
30 def urlsafe_encrypt(key, plaintext, blocksize=16):
31     """
32     Encrypts plaintext. Resulting ciphertext will contain URL-safe characters
33     :param key: AES secret key
34     :param plaintext: Input text to be encrypted
35     :param blocksize: Non-zero integer multiple of AES blocksize in bytes (16)
36
37     :returns : Resulting ciphertext
38     """
39     def pad(text):
40         """
41         Pads text to be encrypted
42         """
43         pad_length = (blocksize - len(text) % blocksize)
44         sr = random.StrongRandom()
45         pad = ''.join(chr(sr.randint(1, 0xFF)) for i in range(pad_length - 1))
46         # We use chr(0) as a delimiter between text and padding
47         return text + chr(0) + pad
48
49     # random initial 16 bytes for CBC
50     init_vector = Random.get_random_bytes(16)
51     cypher = AES.new(key, AES.MODE_CBC, init_vector)
52     padded = cypher.encrypt(pad(str(plaintext)))
53     return base64.urlsafe_b64encode(init_vector + padded)
54
55
56 def urlsafe_decrypt(key, ciphertext):
57     """
58     Decrypts URL-safe base64 encoded ciphertext
59     :param key: AES secret key
60     :param ciphertext: The encrypted text to decrypt
61
62     :returns : Resulting plaintext
63     """
64     # Cast from unicode
65     ciphertext = base64.urlsafe_b64decode(str(ciphertext))
66     cypher = AES.new(key, AES.MODE_CBC, ciphertext[:16])
67     padded = cypher.decrypt(ciphertext[16:])
68     return padded[:padded.rfind(chr(0))]