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. 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 __init__(self, rand_size: int, rand_k: bytearray, size_s: int) -> None: """ Initialize the random object. Args: rand_size: Size of the generated random variable (in bytes). rand_k: Initial filling (seed). size_s: Size of the initial filling (in bytes). """ self._size_s = size_s self._rand_u = bytearray(b'') if rand_k == bytearray(b''): self._rand_u = bytearray( os.urandom(self._size_s) + b'\x00' * (_SIZE_M - self._size_s - 1)) else: if not check_value(rand_k, self._size_s): raise GOSTRandomError('GOSTRandomError: invalid seed value') self._rand_u = rand_k + bytearray(b'\x00' * (_SIZE_M - self._size_s - 1)) self._rand_u = bytearray(self._rand_u) self._q = rand_size // _SIZE_H self._r = rand_size % _SIZE_H self._limit = 2**((_SIZE_M - self._size_s) * 8) self._hash_obj = GOST34112012('streebog512', data=bytearray(b''))
def verify(self, public_key: Any, digest: bytearray, signature: bytearray) -> bool: """ Verify a signature. Args: public_key: Public signature key (as a byte object). digest: Digest for which to be checked signature (as a byte object). signature: Signature of the digest being checked (as a byte object). Returns: The result of the signature verification ('True' or 'False'). Raises: GOSTSignatureError('GOSTSignatureError: invalid public key value'): If the public key value is incorrect. GOSTSignatureError('GOSTSignatureError: invalid signature value'): If the signature value is incorrect. GOSTSignatureError('GOSTSignatureError: invalid digest value'): If the digest value is incorrect. """ if not check_value(public_key, self._size * 2): raise GOSTSignatureError( 'GOSTSignatureError: invalid public key value') if not check_value(signature, self._size * 2): raise GOSTSignatureError( 'GOSTSignatureError: invalid signature value') if not check_value(digest, self._size): raise GOSTSignatureError( 'GOSTSignatureError: invalid digest value') public_key = (bytearray_to_int(public_key[:self._size]), bytearray_to_int(public_key[self._size:])) sign_r, sign_s = self._get_r_s(signature) if not self._verify_step_1(sign_r, sign_s): return False sign_e = self._set_e(digest) sign_v = self._invert(sign_e, self._q) sign_z_1 = sign_s * sign_v % self._q sign_z_2 = self._q - sign_r * sign_v % self._q sign_p = self._mul_point(sign_z_1) sign_q = self._mul_point(sign_z_2, public_key[0], public_key[1]) sign_c = self._add(sign_p[0], sign_q[0], sign_p[1], sign_q[1]) sign_r_check = sign_c[0] % self._q return compare(int_to_bytearray(sign_r_check, self._size), int_to_bytearray(sign_r, self._size))
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, rand_size: int, rand_k: bytearray, size_s: int) -> None: """Initialize the random object.""" self._size_s = size_s if rand_k == bytearray(b''): self._rand_u = os.urandom(self._size_s) + b'\x00' * (_SIZE_M - self._size_s - 1) self._rand_u = bytearray(self._rand_u) else: if not check_value(rand_k, self._size_s): raise GOSTRandomError('invalid seed value') self._rand_u = rand_k + bytearray(b'\x00' * (_SIZE_M - self._size_s - 1)) self._rand_u = bytearray(self._rand_u) self._q = rand_size // _SIZE_H self._r = rand_size % _SIZE_H self._limit = 2 ** (_SIZE_M - self._size_s) self._hash_obj = GOST34112012('streebog512', data=b'')
def public_key_generate(self, private_key: Any) -> bytearray: """ Generate a public key. Parameters - private_key: private signature key (as a byte object). Return: public key (as a byte object). Exception - GOSTSignatureError('invalid private key') - if the private key value is incorrect. """ if not check_value(private_key, self._size): raise GOSTSignatureError('invalid private key') private_key = bytearray_to_int(private_key) public_key = self._mul_point(private_key) public_key_x = int_to_bytearray(public_key[0], self._size) public_key_y = int_to_bytearray(public_key[1], self._size) private_key = 0 return public_key_x + public_key_y
def public_key_generate(self, private_key: Any) -> bytearray: """ Generate a public key. Args: private_key: Private signature key (as a byte object). Returns: Public key (as a byte object). Raises: GOSTSignatureError('GOSTSignatureError: invalid private key'): If the private key value is incorrect. """ if not check_value(private_key, self._size): raise GOSTSignatureError('GOSTSignatureError: invalid private key') private_key = bytearray_to_int(private_key) public_key = self._mul_point(private_key) public_key_x = int_to_bytearray(public_key[0], self._size) public_key_y = int_to_bytearray(public_key[1], self._size) private_key = 0 return public_key_x + public_key_y
def reset(self, rand_k: bytearray = bytearray(b'')): """ Reset the counter and setting a new initial filling. Parameters - rand_k: new initial filling (seed). If this argument is not passed to the function, the 'os.urandom' function is used to generate the initial filling. Exception - GOSTRandomError('invalid seed value'): in case of invalid size of initial filling. """ if rand_k == bytearray(b''): self._rand_u = os.urandom(self._size_s) + b'\x00' * (_SIZE_M - self._size_s - 1) self._rand_u = bytearray(self._rand_u) else: if not check_value(rand_k, self._size_s): raise GOSTRandomError('invalid seed value') self._rand_u = rand_k + b'\x00' * (_SIZE_M - self._size_s - 1) self._rand_u = bytearray(self._rand_u) self._hash_obj.reset()
def reset(self, rand_k: bytearray = bytearray(b'')) -> None: """ Reset the counter and setting a new initial filling. Args: rand_k: New initial filling (seed). If this argument is not passed to the function, the 'os.urandom' function is used to generate the initial filling. Raises: GOSTRandomError('GOSTRandomError: invalid seed value'): In case of invalid value of initial filling. """ if rand_k == bytearray(b''): self._rand_u = bytearray( os.urandom(self._size_s) + bytearray(b'\x00' * (_SIZE_M - self._size_s - 1))) else: if not check_value(rand_k, self._size_s): raise GOSTRandomError('GOSTRandomError: invalid seed value') self._rand_u = rand_k + b'\x00' * (_SIZE_M - self._size_s - 1) self._rand_u = bytearray(self._rand_u) self._hash_obj.reset()