+ prev = bs * b"\x00"
+ for i in xrange(0, tail_offset, bs):
+ prev = encrypter(strxor(data[i:i + bs], prev))
+ tail = data[tail_offset:]
+ return encrypter(strxor(
+ strxor(pad3(tail, bs), prev),
+ k1 if len(tail) == bs else k2,
+ ))
+
+
+def acpkm_master(algo_class, encrypter, key_section_size, bs, keymat_len):
+ """ACPKM-Master key derivation
+
+ :param algo_class: pygost.gost3412's algorithm class
+ :param encrypter: encrypting function, that takes block as an input
+ :param int key_section_size: ACPKM'es key section size (T*), in bytes
+ :param int bs: cipher's blocksize, bytes
+ :param int keymat_len: length of key material to produce
+ """
+ return ctr_acpkm(
+ algo_class,
+ encrypter,
+ key_section_size,
+ bs,
+ data=b"\x00" * keymat_len,
+ iv=b"\xFF" * (bs // 2),
+ )
+
+
+def mac_acpkm_master(algo_class, encrypter, key_section_size, section_size, bs, data):
+ """OMAC-ACPKM-Master
+
+ :param algo_class: pygost.gost3412's algorithm class
+ :param encrypter: encrypting function, that takes block as an input
+ :param int key_section_size: ACPKM'es key section size (T*), in bytes
+ :param int section_size: ACPKM'es section size (N), in bytes
+ :param int bs: cipher's blocksize, bytes
+ :param bytes data: data to authenticate
+ """
+ if len(data) % bs == 0:
+ tail_offset = len(data) - bs
+ else:
+ tail_offset = len(data) - (len(data) % bs)
+ prev = bs * b"\x00"
+ sections = len(data) // section_size
+ if len(data) % section_size != 0:
+ sections += 1
+ keymats = acpkm_master(
+ algo_class,
+ encrypter,
+ key_section_size,
+ bs,
+ (KEYSIZE + bs) * sections,
+ )