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 _add(self, x_1: int, x_2: int, y_1: int, y_2: int) -> Tuple[int, int]: compare_x = compare(int_to_bytearray(x_1, self._size), int_to_bytearray(x_2, self._size)) compare_y = compare(int_to_bytearray(y_1, self._size), int_to_bytearray(y_2, self._size)) if compare_x and compare_y: grad = (3 * x_1 * x_1 + self._a) * self._invert(2 * y_1, self._p) % self._p else: d_x = (x_2 - x_1) % self._p d_y = (y_2 - y_1) % self._p grad = (d_y * self._invert(d_x, self._p)) % self._p x_3 = (grad * grad - x_1 - x_2) % self._p y_3 = (grad * (x_1 - x_3) - y_1) % self._p return x_3, y_3
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 _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 _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 _u_first(self) -> bytearray: self._hmac_obj.reset() self._hmac_obj.update(self._salt + int_to_bytearray(self._counter, 4)) return self._hmac_obj.digest()
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)