def __init__(self, algorithm: str, key: bytearray) -> None: """ Initialize the ciphering object. Args: algorithm: The string with the name of the ciphering algorithm. key: The encryption key. Raises: GOSTCipherError('GOSTCipherError: unsupported cipher algorithm'): In case of unsupported cipher algorithm (is not 'kuznechik' or 'magma'). GOSTCipherError('GOSTCipherError: invalid key value'): In case of invalid 'key' value (the key value is not a byte object ('bytearray' or 'bytes') or its length is not 256 bits). """ if algorithm not in ('magma', 'kuznechik'): key = zero_fill(key) raise GOSTCipherError( 'GOSTCipherError: unsupported cipher algorithm') if not check_value(key, _KEY_SIZE): key = zero_fill(key) raise GOSTCipherError('GOSTCipherError: invalid key value') if algorithm == 'kuznechik': self._cipher_obj: CipherObjType = GOST34122015Kuznechik(key) elif algorithm == 'magma': self._cipher_obj = GOST34122015Magma(key) self.oid = self._cipher_obj.oid
def random(self) -> bytearray: """ Generate the next value from a pseudo-random sequence. Return: new random value. Exception - GOSTRandomError ('exceeded the limit value of the counter'): when the counter limit is exceeded. - GOSTRandomError('the seed value is zero'): if the seed value is zero. """ if bytearray_to_int(self._rand_u[:self._size_s]) == 0: raise GOSTRandomError('the seed value is zero') i = self._q result = bytearray(0) while i > 0: if bytearray_to_int(self._rand_u[self._size_s::]) >= self._limit: self._rand_u = zero_fill(self._rand_u) raise GOSTRandomError('exceeded the limit value of the counter') self._inc_rand_u() self._hash_obj.update(self._rand_u) rand_c = self._hash_obj.digest() self._hash_obj.reset() result = result + rand_c i = i - 1 if self._r != 0: if bytearray_to_int(self._rand_u[self._size_s::]) >= self._limit: self._rand_u = zero_fill(self._rand_u) raise GOSTRandomError('exceeded the limit value of the counter') self._inc_rand_u() self._hash_obj.update(self._rand_u) rand_c = self._hash_obj.digest() self._hash_obj.reset() result = result + rand_c[_SIZE_H - self._r:_SIZE_H:] return result
def _expand_iter_key_final(self, key: bytearray) -> None: for j in range(8): iter_key = bytearray(4) for i in range(4): iter_key[i] = key[28 - (j * 4) + i] self._cipher_iter_key.append(iter_key) iter_key = zero_fill(iter_key) key = zero_fill(key)
def sign( self, private_key: bytearray, digest: bytearray, rand_k: bytearray = bytearray(b'')) -> bytearray: """ Create a signature. Args: private_key: Private signature key (as a byte object). digest: Digest for which the signature is calculated. This value must be obtained using the 'streebog' algorithm in accordance with GOST 34.11-2012. rand_k: Random (pseudo-random) number (as a byte object). By default, it is generated by the function itself. Returns: Signature for provided digest (as a byte object). Raises: GOSTSignatureError('GOSTSignatureError: invalid private key value'): If the private key value is incorrect. GOSTSignatureError('GOSTSignatureError: invalid digest value'): If the digest value is incorrect. GOSTSignatureError('GOSTSignatureError: invalid random value'): If the random value is incorrect. """ if not check_value(private_key, self._size): raise GOSTSignatureError( 'GOSTSignatureError: invalid private key value') if not check_value(digest, self._size): raise GOSTSignatureError( 'GOSTSignatureError: invalid digest value') sign_e = self._set_e(digest) sign_r = 0 sign_s = 0 sign_k = 0 if rand_k == bytearray(b''): rand_k = self._get_rand_k() if not isinstance(rand_k, (bytes, bytearray)): private_key = zero_fill(private_key) raise GOSTSignatureError( 'GOSTSignatureError: invalid random value') if bytearray_to_int(rand_k) >= self._q: private_key = zero_fill(private_key) raise GOSTSignatureError( 'GOSTSignatureError: invalid random value') while compare_to_zero(int_to_bytearray(sign_s, self._size)): while compare_to_zero(int_to_bytearray(sign_r, self._size)): sign_k = bytearray_to_int(rand_k) sign_c = self._mul_point(sign_k) sign_r = sign_c[0] % self._q sign_s = (sign_r * bytearray_to_int(private_key) + sign_k * sign_e) % self._q result = int_to_bytearray(sign_r, self._size) + int_to_bytearray( sign_s, self._size) private_key = zero_fill(private_key) return result
def __init__(self, algorithm: str, key: bytearray) -> None: """Initialize the ciphering object.""" if algorithm not in ('magma', 'kuznechik'): key = zero_fill(key) raise GOSTCipherError('unsupported cipher algorithm') if not check_value(key, _KEY_SIZE): key = zero_fill(key) raise GOSTCipherError('invalid key value') if algorithm == 'kuznechik': self._cipher_obj = GOST34122015Kuznechik(key) elif algorithm == 'magma': self._cipher_obj = GOST34122015Magma(key)
def __init__(self, password: bytearray, salt: bytearray, iterations: int) -> None: """Initialize the PBKDF object.""" if not isinstance(password, (bytes, bytearray)): raise GOSTPBKDFError('invalid password value') self._password = bytearray(password) self._salt = salt if self._salt == bytearray(b''): self._salt = bytearray(os.urandom(32)) if not isinstance(self._salt, (bytes, bytearray)): password = zero_fill(password) self._password = zero_fill(self._password) raise GOSTPBKDFError('invalid salt value') self._salt = bytearray(self._salt) self._iterations = iterations self._num_block = 0 self._counter = 0 self._hmac_obj = R5011132016('HMAC_GOSTR3411_2012_512', self._password) password = zero_fill(password)
def _rand_iter(self) -> bytearray: if bytearray_to_int(self._rand_u[self._size_s::]) >= self._limit: self._rand_u = zero_fill(self._rand_u) raise GOSTRandomError( 'GOSTRandomError: exceeded the limit value of the counter') self._inc_rand_u() self._hash_obj.update(self._rand_u) result = self._hash_obj.digest() self._hash_obj.reset() return result
def __init__(self, key: bytearray): """ Initialize the ciphering object. Args: key: Encryption key. """ self.oid = ObjectIdentifier('1.2.643.7.1.1.5.1') self._cipher_iter_key: List[bytearray] = [] self._expand_iter_key(key) self._expand_iter_key(key) self._expand_iter_key(key) self._expand_iter_key_final(key) key = zero_fill(key)
def clear(self) -> None: """Сlear the key value.""" self._hasher_obj.reset() self._key = zero_fill(self._key)
def clear(self): """Сlear the password value.""" self._password = zero_fill(self._password)
def clear(self) -> None: """Clear the counter value.""" if hasattr(self, '_rand_u'): self._rand_u = zero_fill(self._rand_u)
def new(algorithm: str, key: bytearray, mode: int, **kwargs) -> CipherType: """ Create a new ciphering object and returns it. Args: algorithm: The string with the name of the ciphering algorithm of the GOST R 34.12-2015 ('kuznechik' with block size 128 bit or 'magma' with block size 64 bit). key: Byte object with 256-bit encryption key. mode: Mode of operation of the block encryption algorithm (valid value: MODE_CBC, MODE_CFB, MODE_CTR, MODE_ECB,MODE_OFB or MODE_MAC). **init_vect: Byte object with initialization vector. Used in MODE_CTR, MODE_OFB, MODE_CBC and MODE_CFB modes. For MODE_CTR mode, the initialization vector length is equal to half the block size (default value iz '_DEFAULT_IV_CTR'). For MODE_CBC, MODE_OFB and MODE_CFB modes, it is a multiple of the block size (default value is '_DEFAULT_IV'). **data: The data from which to get the MAC (as a byte object). For MODE_MAC mode only. If this argument is passed to a function, you can immediately use the 'digest' (or 'hexdigest') method to calculate the MAC value after calling 'new'. If the argument is not passed to the function, then you must use the 'update(data)' method before the 'digest' (or 'hexdigest') method. **pad_mode: Padding mode for ECB or CBC (the default value is PAD_MODE_1). Returns: New ciphering object. Raises: GOSTCipherError('GOSTCipherError: unsupported cipher mode'): In case of unsupported cipher mode (is not MODE_ECB, MODE_CBC, MODE_CFB, MODE_OFB, MODE_CTR or MODE_MAC). GOSTCipherError('GOSTCipherError: unsupported cipher algorithm'): In case of invalid value 'algorithm'. GOSTCipherError('GOSTCipherError: invalid key value'): In case of invalid 'key' value (the key value is not a byte object ('bytearray' or 'bytes') or its length is not 256 bits). GOSTCipherError('GOSTCipherError: invalid padding mode'): In case padding mode is incorrect (for MODE_ECB and MODE_CBC modes). GOSTCipherError('GOSTCipherError: invalid initialization vector value'): In case initialization vector value is incorrect (for all modes except ECB mode). GOSTCipherError('GOSTCipherError: invalid text data'): In case where the text data is not byte object (for MODE_MAC mode). """ result: Any = None if mode == MODE_ECB: pad_mode = kwargs.get('pad_mode', PAD_MODE_1) result = GOST34132015ecb(algorithm, key, pad_mode) elif mode == MODE_CBC: init_vect = kwargs.get('init_vect', _DEFAULT_IV_KUZNECHIK) if algorithm == 'magma': init_vect = kwargs.get('init_vect', _DEFAULT_IV_CBC_MAGMA) pad_mode = kwargs.get('pad_mode', PAD_MODE_1) result = GOST34132015cbc(algorithm, key, init_vect, pad_mode) elif mode == MODE_CFB: init_vect = kwargs.get('init_vect', _DEFAULT_IV_KUZNECHIK) if algorithm == 'magma': init_vect = kwargs.get('init_vect', _DEFAULT_IV_MAGMA) result = GOST34132015cfb(algorithm, key, init_vect) elif mode == MODE_OFB: init_vect = kwargs.get('init_vect', _DEFAULT_IV_KUZNECHIK) if algorithm == 'magma': init_vect = kwargs.get('init_vect', _DEFAULT_IV_MAGMA) result = GOST34132015ofb(algorithm, key, init_vect) elif mode == MODE_CTR: init_vect = kwargs.get('init_vect', _DEFAULT_IV_CTR_KUZNECHIK) if algorithm == 'magma': init_vect = kwargs.get('init_vect', _DEFAULT_IV_CTR_MAGMA) result = GOST34132015ctr(algorithm, key, init_vect) elif mode == MODE_MAC: data = kwargs.get('data', bytearray(b'')) result = GOST34132015mac(algorithm, key, data) else: key = zero_fill(key) raise GOSTCipherError('GOSTCipherError: unsupported cipher mode') return result
def clear(self) -> None: """Сlearing the values of iterative encryption keys.""" for i in range(32): self._cipher_iter_key[i] = zero_fill(self._cipher_iter_key[i])
def clear(self): """Clear the counter value.""" self._rand_u = zero_fill(self._rand_u)