codekingpro/portable-devtools
114k
1"""2 authlib.jose.rfc75183 ~~~~~~~~~~~~~~~~~~~~4 5 Cryptographic Algorithms for Cryptographic Algorithms for Content6 Encryption per `Section 5`_.7 8 .. _`Section 5`: https://tools.ietf.org/html/rfc7518#section-59"""10import hmac11import hashlib12from cryptography.hazmat.backends import default_backend13from cryptography.hazmat.primitives.ciphers import Cipher14from cryptography.hazmat.primitives.ciphers.algorithms import AES15from cryptography.hazmat.primitives.ciphers.modes import GCM, CBC16from cryptography.hazmat.primitives.padding import PKCS717from cryptography.exceptions import InvalidTag18from ..rfc7516 import JWEEncAlgorithm19from .util import encode_int20 21 22class CBCHS2EncAlgorithm(JWEEncAlgorithm):23 # The IV used is a 128-bit value generated randomly or24 # pseudo-randomly for use in the cipher.25 IV_SIZE = 12826 27 def __init__(self, key_size, hash_type):28 self.name = f'A{key_size}CBC-HS{hash_type}'29 tpl = 'AES_{}_CBC_HMAC_SHA_{} authenticated encryption algorithm'30 self.description = tpl.format(key_size, hash_type)31 32 # bit length33 self.key_size = key_size34 # byte length35 self.key_len = key_size // 836 37 self.CEK_SIZE = key_size * 238 self.hash_alg = getattr(hashlib, f'sha{hash_type}')39 40 def _hmac(self, ciphertext, aad, iv, key):41 al = encode_int(len(aad) * 8, 64)42 msg = aad + iv + ciphertext + al43 d = hmac.new(key, msg, self.hash_alg).digest()44 return d[:self.key_len]45 46 def encrypt(self, msg, aad, iv, key):47 """Key Encryption with AES_CBC_HMAC_SHA2.48 49 :param msg: text to be encrypt in bytes50 :param aad: additional authenticated data in bytes51 :param iv: initialization vector in bytes52 :param key: encrypted key in bytes53 :return: (ciphertext, iv, tag)54 """55 self.check_iv(iv)56 hkey = key[:self.key_len]57 ekey = key[self.key_len:]58 59 pad = PKCS7(AES.block_size).padder()60 padded_data = pad.update(msg) + pad.finalize()61 62 cipher = Cipher(AES(ekey), CBC(iv), backend=default_backend())63 enc = cipher.encryptor()64 ciphertext = enc.update(padded_data) + enc.finalize()65 tag = self._hmac(ciphertext, aad, iv, hkey)66 return ciphertext, tag67 68 def decrypt(self, ciphertext, aad, iv, tag, key):69 """Key Decryption with AES AES_CBC_HMAC_SHA2.70 71 :param ciphertext: ciphertext in bytes72 :param aad: additional authenticated data in bytes73 :param iv: initialization vector in bytes74 :param tag: authentication tag in bytes75 :param key: encrypted key in bytes76 :return: message77 """78 self.check_iv(iv)79 hkey = key[:self.key_len]80 dkey = key[self.key_len:]81 82 _tag = self._hmac(ciphertext, aad, iv, hkey)83 if not hmac.compare_digest(_tag, tag):84 raise InvalidTag()85 86 cipher = Cipher(AES(dkey), CBC(iv), backend=default_backend())87 d = cipher.decryptor()88 data = d.update(ciphertext) + d.finalize()89 unpad = PKCS7(AES.block_size).unpadder()90 return unpad.update(data) + unpad.finalize()91 92 93class GCMEncAlgorithm(JWEEncAlgorithm):94 # Use of an IV of size 96 bits is REQUIRED with this algorithm.95 # https://tools.ietf.org/html/rfc7518#section-5.396 IV_SIZE = 9697 98 def __init__(self, key_size):99 self.name = f'A{key_size}GCM'100 self.description = f'AES GCM using {key_size}-bit key'101 self.key_size = key_size102 self.CEK_SIZE = key_size103 104 def encrypt(self, msg, aad, iv, key):105 """Key Encryption with AES GCM106 107 :param msg: text to be encrypt in bytes108 :param aad: additional authenticated data in bytes109 :param iv: initialization vector in bytes110 :param key: encrypted key in bytes111 :return: (ciphertext, iv, tag)112 """113 self.check_iv(iv)114 cipher = Cipher(AES(key), GCM(iv), backend=default_backend())115 enc = cipher.encryptor()116 enc.authenticate_additional_data(aad)117 ciphertext = enc.update(msg) + enc.finalize()118 return ciphertext, enc.tag119 120 def decrypt(self, ciphertext, aad, iv, tag, key):121 """Key Decryption with AES GCM122 123 :param ciphertext: ciphertext in bytes124 :param aad: additional authenticated data in bytes125 :param iv: initialization vector in bytes126 :param tag: authentication tag in bytes127 :param key: encrypted key in bytes128 :return: message129 """130 self.check_iv(iv)131 cipher = Cipher(AES(key), GCM(iv, tag), backend=default_backend())132 d = cipher.decryptor()133 d.authenticate_additional_data(aad)134 return d.update(ciphertext) + d.finalize()135 136 137JWE_ENC_ALGORITHMS = [138 CBCHS2EncAlgorithm(128, 256), # A128CBC-HS256139 CBCHS2EncAlgorithm(192, 384), # A192CBC-HS384140 CBCHS2EncAlgorithm(256, 512), # A256CBC-HS512141 GCMEncAlgorithm(128), # A128GCM142 GCMEncAlgorithm(192), # A192GCM143 GCMEncAlgorithm(256), # A256GCM144]145 