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 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 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 _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 _get_mac_key(self, value_r): value_b = b'' if self.block_size == 16: value_b = _B_128 elif self.block_size == 8: value_b = _B_64 if msb(value_r) == 0: int_value = bytearray_to_int(value_r) << 1 key_1 = int_to_bytearray(int_value, self.block_size) else: int_value = bytearray_to_int(value_r) << 1 key_1 = add_xor(int_to_bytearray(int_value, self.block_size), value_b) if msb(key_1) == 0: int_value = bytearray_to_int(key_1) << 1 key_2 = int_to_bytearray(int_value, self.block_size) else: int_value = bytearray_to_int(key_1) << 1 key_2 = add_xor(int_to_bytearray(int_value, self.block_size), value_b) return [key_1, key_2]
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 random(self) -> bytearray: """ Generate the next value from a pseudo-random sequence. Returns: New random value. Raises: GOSTRandomError ('GOSTRandomError: exceeded the limit value of the counter'): When the counter limit is exceeded. GOSTRandomError('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('GOSTRandomError: the seed value is zero') i = self._q result = bytearray(0) while i > 0: result = result + self._rand_iter() i = i - 1 if self._r != 0: result = result + self._rand_iter()[_SIZE_H - self._r:_SIZE_H:] return result
import unittest import os import pytest from unittest import mock import gostcrypto from gostcrypto.utils import bytearray_to_int from gostcrypto.utils import int_to_bytearray from gostcrypto.gostsignature import GOSTSignatureError TEST_CURVE = { 'id-tc26-gost-3410-2012-256-paramSetTest':dict( p=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000000000000000000000000000000000431')), a=0x07, b=bytearray_to_int(bytearray.fromhex('5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e')), m=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3')), q=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3')), x=0x02, y=bytearray_to_int(bytearray.fromhex('08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8')) ), 'id-tc26-gost-3410-2012-256-paramSetTest_raises_1':dict( p=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3')), a=0x07, b=bytearray_to_int(bytearray.fromhex('5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e')), m=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3')), q=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3')), x=0x02, y=bytearray_to_int(bytearray.fromhex('08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8')) ), 'id-tc26-gost-3410-2012-256-paramSetTest_raises_2':dict( p=bytearray_to_int(bytearray.fromhex('8000000000000000000000000000000000000000000000000000000000000431')),
def _get_r_s(self, signature: bytearray) -> Tuple[int, int]: sign_r = bytearray_to_int(signature[:self._size]) sign_s = bytearray_to_int(signature[self._size:]) return sign_r, sign_s
def _set_e(self, digest: bytearray) -> int: result = bytearray_to_int(digest) % self._q if compare_to_zero(int_to_bytearray(result, self._size)): result = 1 return result
def _get_rand_k(self) -> bytearray: rand_k = bytearray(os.urandom(self._size)) while bytearray_to_int(rand_k) >= self._q: rand_k = bytearray(os.urandom(self._size)) return rand_k
from gostcrypto.utils import bytearray_to_int from gostcrypto.utils import int_to_bytearray from gostcrypto.utils import compare from gostcrypto.utils import compare_to_zero from gostcrypto.utils import check_value from gostcrypto.gostoid import ObjectIdentifier MODE_256: int = 0x01 MODE_512: int = 0x02 # pylint: disable=R0801 CURVES_R_1323565_1_024_2019: dict = { 'id-tc26-gost-3410-2012-256-paramSetB': dict(p=bytearray_to_int( bytearray([ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x97 ])), a=bytearray_to_int( bytearray([ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x94 ])), b=0xa6, m=bytearray_to_int( bytearray([ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6c, 0x61, 0x10, 0x70, 0x99, 0x5a, 0xd1, 0x00, 0x45, 0x84, 0x1b, 0x09, 0xb7,
def _inc_rand_u(self) -> None: int_rand_u = bytearray_to_int(self._rand_u) + 1 % (2**(_SIZE_M - 1)) self._rand_u = int_to_bytearray(int_rand_u, _SIZE_M - 1)