This commit is contained in:
Helder Eijs 2022-11-27 23:30:55 +01:00
parent 6b7e0ed106
commit 9abdf1aff5
10 changed files with 401 additions and 52 deletions

View file

@ -28,14 +28,12 @@
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
import os
import re
import unittest
from binascii import hexlify, unhexlify
from binascii import unhexlify
from Crypto.Util.py3compat import b, tobytes, bchr
from Crypto.Util.strxor import strxor_c
from Crypto.Util.number import long_to_bytes
from Crypto.SelfTest.loader import load_test_vectors
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Cipher import AES
@ -417,10 +415,6 @@ class OcbFSMTests(unittest.TestCase):
for method_name in "encrypt", "decrypt":
for auth_data in (None, b("333"), self.data,
self.data + b("3")):
if auth_data is None:
assoc_len = None
else:
assoc_len = len(auth_data)
cipher = AES.new(self.key_128, AES.MODE_OCB,
nonce=self.nonce_96)
if auth_data is not None:
@ -503,6 +497,35 @@ class OcbFSMTests(unittest.TestCase):
self.data)
def algo_rfc7253(keylen, taglen, noncelen):
"""Implement the algorithm at page 18 of RFC 7253"""
key = bchr(0) * (keylen // 8 - 1) + bchr(taglen)
C = b""
for i in range(128):
S = bchr(0) * i
N = long_to_bytes(3 * i + 1, noncelen // 8)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(S)
C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
N = long_to_bytes(3 * i + 2, noncelen // 8)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
N = long_to_bytes(3 * i + 3, noncelen // 8)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(S)
C += cipher.encrypt() + cipher.digest()
N = long_to_bytes(385, noncelen // 8)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(C)
return cipher.encrypt() + cipher.digest()
class OcbRfc7253Test(unittest.TestCase):
# Tuple with
@ -665,7 +688,7 @@ class OcbRfc7253Test(unittest.TestCase):
def test1(self):
key = unhexlify(b(self.tv1_key))
for tv in self.tv1:
nonce, aad, pt, ct = [ unhexlify(b(x)) for x in tv ]
nonce, aad, pt, ct = [unhexlify(b(x)) for x in tv]
ct, mac_tag = ct[:-16], ct[-16:]
cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
@ -682,7 +705,7 @@ class OcbRfc7253Test(unittest.TestCase):
def test2(self):
key, nonce, aad, pt, ct = [ unhexlify(b(x)) for x in self.tv2 ]
key, nonce, aad, pt, ct = [unhexlify(b(x)) for x in self.tv2]
ct, mac_tag = ct[:-12], ct[-12:]
cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12)
@ -698,41 +721,79 @@ class OcbRfc7253Test(unittest.TestCase):
cipher.verify(mac_tag)
def test3(self):
for keylen, taglen, result in self.tv3:
key = bchr(0) * (keylen // 8 - 1) + bchr(taglen)
C = b("")
for i in range(128):
S = bchr(0) * i
N = long_to_bytes(3 * i + 1, 12)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(S)
C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
N = long_to_bytes(3 * i + 2, 12)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
N = long_to_bytes(3 * i + 3, 12)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(S)
C += cipher.encrypt() + cipher.digest()
N = long_to_bytes(385, 12)
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
cipher.update(C)
result2 = cipher.encrypt() + cipher.digest()
result2 = algo_rfc7253(keylen, taglen, 96)
self.assertEqual(unhexlify(b(result)), result2)
class OcbDkgTest(unittest.TestCase):
"""Test vectors from https://gitlab.com/dkg/ocb-test-vectors"""
def test_nonce120(self):
key = unhexlify("0F0E0D0C0B0A09080706050403020100")
def test_1_2(self):
tvs = []
for fi in (1, 2):
for nb in (104, 112, 120):
tv_file = load_test_vectors(("Cipher", "AES"),
"test-vector-%d-nonce%d.txt" % (fi, nb),
"DKG tests, %d, %d bits" % (fi, nb),
{})
if tv_file is None:
break
key = tv_file[0].k
for tv in tv_file[1:]:
tv.k = key
tvs.append(tv)
for tv in tvs:
k, n, a, p, c = tv.k, tv.n, tv.a, tv.p, tv.c
mac_len = len(c) - len(p)
cipher = AES.new(k, AES.MODE_OCB, nonce=n, mac_len=mac_len)
cipher.update(a)
c_out, tag_out = cipher.encrypt_and_digest(p)
self.assertEqual(c, c_out + tag_out)
def test_3(self):
def check(keylen, taglen, noncelen, exp):
result = algo_rfc7253(keylen, taglen, noncelen)
self.assertEqual(result, unhexlify(exp))
# test-vector-3-nonce104.txt
check(128, 128, 104, "C47F5F0341E15326D4D1C46F47F05062")
check(192, 128, 104, "95B9167A38EB80495DFC561A8486E109")
check(256, 128, 104, "AFE1CDDB97028FD92F8FB3C8CFBA7D83")
check(128, 96, 104, "F471B4983BA80946DF217A54")
check(192, 96, 104, "5AE828BC51C24D85FA5CC7B2")
check(256, 96, 104, "8C8335982E2B734616CAD14C")
check(128, 64, 104, "B553F74B85FD1E5B")
check(192, 64, 104, "3B49D20E513531F9")
check(256, 64, 104, "ED6DA5B1216BF8BB")
# test-vector-3-nonce112.txt
check(128, 128, 112, "CA8AFCA031BAC3F480A583BD6C50A547")
check(192, 128, 112, "D170C1DF356308079DA9A3F619147148")
check(256, 128, 112, "57F94381F2F9231EFB04AECD323757C3")
check(128, 96, 112, "3A618B2531ED39F260C750DC")
check(192, 96, 112, "9071EB89FEDBADDA88FD286E")
check(256, 96, 112, "FDF0EFB97F21A39AC4BAB5AC")
check(128, 64, 112, "FAB2FF3A8DD82A13")
check(192, 64, 112, "AC01D912BD0737D3")
check(256, 64, 112, "9D1FD0B500EA4ECF")
# test-vector-3-nonce120.txt
check(128, 128, 120, "9E043A7140A25FB91F43BCC9DD7E0F46")
check(192, 128, 120, "680000E53908323A7F396B955B8EC641")
check(256, 128, 120, "8304B97FAACDA56E676602E1878A7E6F")
check(128, 96, 120, "81F978AC9867E825D339847D")
check(192, 96, 120, "EFCF2D60B24926ADA48CF5B1")
check(256, 96, 120, "84961DC56E917B165E58C174")
check(128, 64, 120, "227AEE6C9D905A61")
check(192, 64, 120, "541DE691B9E1A2F9")
check(256, 64, 120, "B0E761381C7129FC")
def test_2_bugfix(self):
nonce = unhexlify("EEDDCCBBAA9988776655443322110D")
key = unhexlify("0F0E0D0C0B0A09080706050403020100")
A = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617"
"18191A1B1C1D1E1F2021222324252627")
P = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617"
@ -742,12 +803,6 @@ class OcbDkgTest(unittest.TestCase):
"C236A7B3")
mac_len = len(C) - len(P)
cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=mac_len)
cipher.update(A)
C_out, tag_out = cipher.encrypt_and_digest(P)
self.assertEqual(C, C_out + tag_out)
# Prior to version 3.17, a nonce of maximum length (15 bytes)
# was actually used as a 14 byte nonce. The last byte was erroneously
# ignored.
@ -771,6 +826,6 @@ def get_tests(config={}):
if __name__ == '__main__':
import unittest
suite = lambda: unittest.TestSuite(get_tests())
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')

View file

@ -115,12 +115,41 @@ def _load_tests(dir_comps, file_in, description, conversions):
def load_test_vectors(dir_comps, file_name, description, conversions):
"""Load and parse a test vector file
"""Load and parse a test vector file, formatted using the NIST style.
This function returns a list of objects, one per group of adjacent
KV lines or for a single line in the form "[.*]".
Args:
dir_comps (list of strings):
The path components under the ``pycryptodome_test_vectors`` package.
For instance ``("Cipher", "AES")``.
file_name (string):
The name of the file with the test vectors.
description (string):
A description applicable to the test vectors in the file.
conversions (dictionary):
The dictionary contains functions.
Values in the file that have an entry in this dictionary
will be converted usign the matching function.
Otherwise, values will be considered as hexadecimal and
converted to binary.
For a group of lines, the object has one attribute per line.
Returns:
A list of test vector objects.
The file is formatted in the following way:
- Lines starting with "#" are comments and will be ignored.
- Each test vector is a sequence of 1 or more adjacent lines, where
each lines is an assignement.
- Test vectors are separated by an empty line, a comment, or
a line starting with "[".
A test vector object has the following attributes:
- desc (string): description
- counter (int): the order of the test vector in the file (from 1)
- others (list): zero or more lines of the test vector that were not assignments
- left-hand side of each assignment (lowercase): the value of the
assignement, either converted or bytes.
"""
results = None

View file

@ -4,6 +4,10 @@ Files downloaded from the NIST website on November 8, 2015 as:
* http://csrc.nist.gov/groups/STM/cavp/documents/aes/aesmct.zip
* http://csrc.nist.gov/groups/STM/cavp/documents/aes/aesmmt.zip
And on December 16, 2015 as:
Files downloaded on December 16, 2015 as:
* http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip
Files downloaded on November 28, 2022 as:
* https://gitlab.com/dkg/ocb-test-vectors

View file

@ -0,0 +1,81 @@
K = 000102030405060708090A0B0C0D0E0F
N = CCBBAA99887766554433221100
A =
P =
C = 1AF957957B85C3D7F6CA08C7C5FC8F4A
N = CCBBAA99887766554433221101
A = 0001020304050607
P = 0001020304050607
C = F4132F7B364D13A2303ACE52DDF90774E24E3E8895AC7F88
N = CCBBAA99887766554433221102
A = 0001020304050607
P =
C = 20E9B13D02F7B19AFDC4659344960BED
N = CCBBAA99887766554433221103
A =
P = 0001020304050607
C = 4A2A7E6D7A0A0EA4D652CC24F2208986E47B3251A66B5944
N = CCBBAA99887766554433221104
A = 000102030405060708090A0B0C0D0E0F
P = 000102030405060708090A0B0C0D0E0F
C = EEED2C9E7CFA9580551B03DCDB2E1DFA4A60E8225633281B98173DD6F1F1A57F
N = CCBBAA99887766554433221105
A = 000102030405060708090A0B0C0D0E0F
P =
C = 19BAE49F721302071167C34E02A8BE9B
N = CCBBAA99887766554433221106
A =
P = 000102030405060708090A0B0C0D0E0F
C = E254116668AEC1D2663E3E9B914AC47D0337401A0B16E4605B94A2C45F0F53CB
N = CCBBAA99887766554433221107
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = 0C0299BEE2D5B65CBC82A6EE119543B7B89DE85561D149BFC1CBE6EC8749065C6068E046FB2BA7F7
N = CCBBAA99887766554433221108
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P =
C = F4E603C017B49123CD3EEBF0F342DE31
N = CCBBAA99887766554433221109
A =
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = 9A2D75CA34639FF92CACDD3A881ED446B0E790D719A9DFD680C97FAE8ECE18A03A4C67DC1C0763B6
N = CCBBAA9988776655443322110A
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = 0FEBCFA18BF3D2C4C155266755817F843DFA5A5CFD8987D87BE45F3669599D66B2D98602565E18AC31AD88C7C51A6988
N = CCBBAA9988776655443322110B
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P =
C = 6F48A1E1F0D43023CFA84F4143E286B8
N = CCBBAA9988776655443322110C
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = 1DF09EC159EB74B3B4AC4B440D2D382ADE25D3A26D9A2A2EDCF23F41002FB7EB53417D8AFED547BFD54056BC9EA9C590
N = CCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 3BCFFDEAC246CB305D367A25489ACE1F8FF0317260401B9E1A08DA6C11A0CC490871BD1A5E4FA29FF0E0A7326F0F871583AA3FAE224DD5EB
N = CCBBAA9988776655443322110E
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P =
C = FA7B7AC1ABD4097F4D547BE9FD5D0BB2
N = CCBBAA9988776655443322110F
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = C8B16DA1C0AC72E4C993AC75EBD800D0ECDC45EE9DDC2D70C74BA3E4EFCC98A9DF77F8560D7EB2C33EDE4A46D9A2AD0CCAEB653BB6D38725

View file

@ -0,0 +1,81 @@
K = 000102030405060708090A0B0C0D0E0F
N = DDCCBBAA99887766554433221100
A =
P =
C = B22774052013981C3038DA65757A55E4
N = DDCCBBAA99887766554433221101
A = 0001020304050607
P = 0001020304050607
C = 3791C1215BB0F2E3B008F1A9BFF0A2069BD2B3B93168AD17
N = DDCCBBAA99887766554433221102
A = 0001020304050607
P =
C = C07EDDBB4359D5E68F7618E7D397BFAC
N = DDCCBBAA99887766554433221103
A =
P = 0001020304050607
C = AF02506326B86248936845A600CEC91888F52C214ED1674A
N = DDCCBBAA99887766554433221104
A = 000102030405060708090A0B0C0D0E0F
P = 000102030405060708090A0B0C0D0E0F
C = 165A060B6A9ED2F930A7D6DEC0195B5B19722619DD37749A1B97FF6C63393009
N = DDCCBBAA99887766554433221105
A = 000102030405060708090A0B0C0D0E0F
P =
C = E1616FC25D8A300D8C64CD2018071BFE
N = DDCCBBAA99887766554433221106
A =
P = 000102030405060708090A0B0C0D0E0F
C = 14F2D292673A8F1DA6B80543658784F5DEE9FF8FF1B0A40FD16720E2B2970549
N = DDCCBBAA99887766554433221107
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = 98B9D538E13A8D12CE94C53F7C36675C77C0A8C9BDE234FDB02E92506483A49976AE5585F1777360
N = DDCCBBAA99887766554433221108
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P =
C = 8B3F1EA59A0D5D7C9FD369B6CEE0F4A6
N = DDCCBBAA99887766554433221109
A =
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = AB910BACF2F2409EE871D2818AC31ADFAA39DA637E2D1BF2D87985B4B532966CAF43B13EE754AB07
N = DDCCBBAA9988776655443322110A
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = 635623537A7D54ABB68F5B23E151FFAA77A6E0EC19DF46117C2E990154C74539393E11FBC726AACB37023175DD592667
N = DDCCBBAA9988776655443322110B
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P =
C = 97CC4DE80C67DD335771E498944288BF
N = DDCCBBAA9988776655443322110C
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = A159D066AB9BF3C2B3DC4881BD4DE3A197B12548F11F91972D3B0E881A811AED6427067C99276B1CD0E4382C4C9A8709
N = DDCCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 259731C171E61C6FEE8E55A7B784DAB3B4B75AC8DE8C4A3CC01C96F19EAFA7F4FC49C84220893993A0B48DF8A969ACECD84BBAA996375A4F
N = DDCCBBAA9988776655443322110E
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P =
C = F03AF5CB012CF7228FCAEC2B2B0FFF69
N = DDCCBBAA9988776655443322110F
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 45979D0ACA9A7DA537C96BCDBE1F40A288C9FD0E608148C904DA17ACAC18407E3F5D1D5A9546EA59F9F3A1D13EEF2A13676101371D0BAB20

View file

@ -0,0 +1,81 @@
K = 000102030405060708090A0B0C0D0E0F
N = EEDDCCBBAA99887766554433221100
A =
P =
C = 752ACD2132C41E020E41FB223EFD77B6
N = EEDDCCBBAA99887766554433221101
A = 0001020304050607
P = 0001020304050607
C = 201FE4D89EA7BD1EB5B1577DB16283B8AED1715AD6BE5149
N = EEDDCCBBAA99887766554433221102
A = 0001020304050607
P =
C = 710960B9EE00B8F44D2E8120AABA63AE
N = EEDDCCBBAA99887766554433221103
A =
P = 0001020304050607
C = 084E869570194BD25032FE9E5328E45D507E74F3366E20D2
N = EEDDCCBBAA99887766554433221104
A = 000102030405060708090A0B0C0D0E0F
P = 000102030405060708090A0B0C0D0E0F
C = 9676EE37FD645C07C0D4F70AABF686688E39B2FB3FC4FF30DCD1827B36A298D3
N = EEDDCCBBAA99887766554433221105
A = 000102030405060708090A0B0C0D0E0F
P =
C = 9D510F56EDF72FFA34969BCEF91E6DE9
N = EEDDCCBBAA99887766554433221106
A =
P = 000102030405060708090A0B0C0D0E0F
C = D5E15AA1D232AB57F234366DFFB25574A3636A5F3E3433EA4590CBF4F9AC1F4D
N = EEDDCCBBAA99887766554433221107
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = 1C4B6777B7F137C30971A93DE3C56CC735686A6F7703142FAB8ACC987C1406DFF96273C5376E6210
N = EEDDCCBBAA99887766554433221108
A = 000102030405060708090A0B0C0D0E0F1011121314151617
P =
C = 96E670C0238FB969B7ACE4ABAF7438C7
N = EEDDCCBBAA99887766554433221109
A =
P = 000102030405060708090A0B0C0D0E0F1011121314151617
C = 1290A686D825F712E594BE4039C04D3E44F7D1342B84FFCAD68BBDFA04B580EA9A01E2F4565399C3
N = EEDDCCBBAA9988776655443322110A
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = FBDFC11F749217BB7FAE5D4036B8F22803712EFF9EF94342FE1B684968D0E3E381A277DAAB83579406A01E2675A082C9
N = EEDDCCBBAA9988776655443322110B
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
P =
C = 90CDA8A05161D2873361374B76F95430
N = EEDDCCBBAA9988776655443322110C
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
C = D1320AF4B6FF8AFEECEE7921395D4E8692717753EE15F5038EB674DA43D6EA8DBE7831E723BE471F62D9E7F49A7D3B32
N = EEDDCCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 5C79F1C4B9A204ED3323616D576FC500E4A71939F03A3C3DE2C097AF2C6C81DC3F0309E76082B1F50FF8522959FFE41F37EF507E9076D32C
N = EEDDCCBBAA9988776655443322110E
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P =
C = 3BF158B7DE76C5151EF6086A825D0CC4
N = EEDDCCBBAA9988776655443322110F
A =
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 34DA59D2EB08F47822D48C85B6A1D23694E1D3DE680D616D7B1B59472C13E369C68DCA699DA1686A339D5452803632810B0840E6804AB020

View file

@ -0,0 +1,6 @@
K = 0F0E0D0C0B0A09080706050403020100
N = CCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = E2D96B20C61AF5EE1CB1786F00B78243B624B3F11CF32D5584DEA0CC0C3C0A07C12C526D79892854D8B3A985BFF28291AB82BBA5

View file

@ -0,0 +1,6 @@
K = 0F0E0D0C0B0A09080706050403020100
N = DDCCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 53187118F97E01AE50431EDCEB4919AD1E6604FFE805C9D980AA5311A3D02412E891F573F10F3B08D51617F3AE8A412F3EB1BD30

View file

@ -0,0 +1,6 @@
K = 0F0E0D0C0B0A09080706050403020100
N = EEDDCCBBAA9988776655443322110D
A = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
P = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
C = 07E903BFC49552411ABC865F5ECE60F6FAD1F5A9F14D3070FA2F1308A563207FFE14C1EEA44B22059C7484319D8A2C53C236A7B3

View file

@ -1 +1 @@
__version__ = "1.0.10"
__version__ = "1.0.11"