Skip to content

Commit

Permalink
add hkdf and bug fix
Browse files Browse the repository at this point in the history
  • Loading branch information
stsch9 committed Nov 29, 2023
1 parent 9d3680e commit 9d078c4
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 3 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ crypto_auth_hmacsha512_verify
crypto_auth_hmacsha512256_keygen
crypto_auth_hmacsha512256
crypto_auth_hmacsha512256_verify
crypto_kdf_hkdf_sha256_extract_init(salt=b'')
crypto_kdf_hkdf_sha256_extract_update(state, ikm=b'')
crypto_kdf_hkdf_sha256_extract_final(state)
crypto_kdf_hkdf_sha256_extract(salt=b'', ikm=b'')
crypto_kdf_hkdf_sha256_keygen()
crypto_kdf_hkdf_sha256_expand(outlen, prk, ctx=b'')
```

Constants:
Expand Down Expand Up @@ -242,6 +248,10 @@ crypto_auth_hmacsha512_BYTES
crypto_auth_hmacsha512_KEYBYTES
crypto_auth_hmacsha512256_BYTES
crypto_auth_hmacsha512256_KEYBYTES
crypto_kdf_hkdf_sha256_KEYBYTES
crypto_kdf_hkdf_sha256_BYTES_MIN
crypto_kdf_hkdf_sha256_BYTES_MAX
crypto_kdf_hkdf_sha256_STATEBYTES
```


Expand Down
65 changes: 62 additions & 3 deletions pysodium/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ def wrapper(*args, **kwargs):
crypto_auth_hmacsha512256_BYTES = sodium.crypto_auth_hmacsha512256_bytes()
crypto_auth_hmacsha512256_KEYBYTES = sodium.crypto_auth_hmacsha512256_keybytes()

if sodium_version_check(1, 0, 19):
crypto_kdf_hkdf_sha256_KEYBYTES = sodium.crypto_kdf_hkdf_sha256_keybytes()
crypto_kdf_hkdf_sha256_BYTES_MIN = sodium.crypto_kdf_hkdf_sha256_bytes_min()
crypto_kdf_hkdf_sha256_BYTES_MAX = sodium.crypto_kdf_hkdf_sha256_bytes_max()
crypto_kdf_hkdf_sha256_STATEBYTES = sodium.crypto_kdf_hkdf_sha256_statebytes()

sodium_init = sodium.sodium_init

class CryptoSignState(ctypes.Structure):
Expand Down Expand Up @@ -579,7 +585,7 @@ def crypto_auth_verify(h, m, k):
# void crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]);
def crypto_auth_hmacsha256_keygen():
k = ctypes.create_string_buffer(crypto_auth_hmacsha256_KEYBYTES)
__check(sodium.crypto_auth_hmacsha256_keygen(k))
sodium.crypto_auth_hmacsha256_keygen(k)
return k.raw


Expand Down Expand Up @@ -625,7 +631,7 @@ def crypto_auth_hmacsha256_verify(h, m, k):
# void crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]);
def crypto_auth_hmacsha512_keygen():
k = ctypes.create_string_buffer(crypto_auth_hmacsha512_KEYBYTES)
__check(sodium.crypto_auth_hmacsha512_keygen(k))
sodium.crypto_auth_hmacsha512_keygen(k)
return k.raw


Expand Down Expand Up @@ -671,7 +677,7 @@ def crypto_auth_hmacsha512_verify(h, m, k):
# void crypto_auth_hmacsha512256_keygen(unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]);
def crypto_auth_hmacsha512256_keygen():
k = ctypes.create_string_buffer(crypto_auth_hmacsha512256_KEYBYTES)
__check(sodium.crypto_auth_hmacsha512256_keygen(k))
sodium.crypto_auth_hmacsha512256_keygen(k)
return k.raw


Expand Down Expand Up @@ -1345,6 +1351,59 @@ def crypto_hash_sha512_final(state):
__check(sodium.crypto_hash_sha512_final(state, out))
return out.raw

# int crypto_kdf_hkdf_sha256_extract_init(crypto_kdf_hkdf_sha256_state *state,
# const unsigned char *salt, size_t salt_len)
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_extract_init(salt=b''):
state = ctypes.create_string_buffer(crypto_kdf_hkdf_sha256_STATEBYTES)
__check(sodium.crypto_kdf_hkdf_sha256_extract_init(state, salt, ctypes.c_size_t(len(salt))))
return state

# int crypto_kdf_hkdf_sha256_extract_update(crypto_kdf_hkdf_sha256_state *state,
# const unsigned char *ikm, size_t ikm_len)
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_extract_update(state, ikm=b''):
if len(state) != crypto_kdf_hkdf_sha256_STATEBYTES: raise ValueError("invalid state")
__check(sodium.crypto_kdf_hkdf_sha256_extract_update(state, ikm, ctypes.c_size_t(len(ikm))))
return state

# int crypto_kdf_hkdf_sha256_extract_final(crypto_kdf_hkdf_sha256_state *state,
# unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES])
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_extract_final(state):
if len(state) != crypto_kdf_hkdf_sha256_STATEBYTES: raise ValueError("invalid state")
prk = ctypes.create_string_buffer(crypto_kdf_hkdf_sha256_KEYBYTES)
__check(sodium.crypto_kdf_hkdf_sha256_extract_final(state, prk))
return prk.raw

# int crypto_kdf_hkdf_sha256_extract(
# unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES],
# const unsigned char *salt, size_t salt_len, const unsigned char *ikm,
# size_t ikm_len)
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_extract(salt=b'', ikm=b''):
prk = ctypes.create_string_buffer(crypto_kdf_hkdf_sha256_KEYBYTES)
__check(sodium.crypto_kdf_hkdf_sha256_extract(prk, salt, ctypes.c_size_t(len(salt)), ikm, ctypes.c_size_t(len(ikm))))
return prk.raw

# void crypto_kdf_hkdf_sha256_keygen(unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES])
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_keygen():
k = ctypes.create_string_buffer(crypto_kdf_hkdf_sha256_KEYBYTES)
sodium.crypto_kdf_hkdf_sha256_keygen(k)
return k.raw

# int crypto_kdf_hkdf_sha256_expand(unsigned char *out, size_t out_len,
# const char *ctx, size_t ctx_len,
# const unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES])
@sodium_version(1, 0, 19)
def crypto_kdf_hkdf_sha256_expand(outlen, prk, ctx=b''):
if not (crypto_kdf_hkdf_sha256_BYTES_MIN <= outlen <= crypto_kdf_hkdf_sha256_BYTES_MAX): raise ValueError("invalid output len")
if len(prk) != crypto_kdf_hkdf_sha256_KEYBYTES: raise ValueError("invalid prk")
out = ctypes.create_string_buffer(outlen)
__check(sodium.crypto_kdf_hkdf_sha256_expand(out, ctypes.c_size_t(outlen), ctx, ctypes.c_size_t(len(ctx)), prk))
return out.raw

# int crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES],
# unsigned char sk[crypto_kx_SECRETKEYBYTES]);
@sodium_version(1, 0, 12)
Expand Down
32 changes: 32 additions & 0 deletions test/test_pysodium.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,38 @@ def test_crypto_auth(self):
tag = pysodium.crypto_auth("howdy", sk)
pysodium.crypto_auth_verify(tag, "howdy", sk)

def test_crypto_kdf_hkdf_sha256(self):
# test vectors: https://datatracker.ietf.org/doc/html/rfc5869
if not pysodium.sodium_version_check(1, 0, 19): return
expected_prk = bytes.fromhex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")
expected_out = bytes.fromhex("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
ikm = bytes.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
salt = bytes.fromhex("000102030405060708090a0b0c")
ctx = bytes.fromhex("f0f1f2f3f4f5f6f7f8f9")
outlen = 42
self.assertEqual(expected_prk, pysodium.crypto_kdf_hkdf_sha256_extract(salt, ikm))
self.assertEqual(expected_out, pysodium.crypto_kdf_hkdf_sha256_expand(outlen, expected_prk, ctx))

expected_prk = bytes.fromhex("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244")
expected_out = bytes.fromhex("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87")
ikm = bytes.fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")
salt = bytes.fromhex("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf")
ctx = bytes.fromhex("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
outlen = 82
self.assertEqual(expected_prk, pysodium.crypto_kdf_hkdf_sha256_extract(salt, ikm))
self.assertEqual(expected_out, pysodium.crypto_kdf_hkdf_sha256_expand(outlen, expected_prk, ctx))

expected_prk = bytes.fromhex("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04")
expected_out = bytes.fromhex("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")
ikm = bytes.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
salt = bytes.fromhex("")
ctx = bytes.fromhex("")
outlen = 42
state = pysodium.crypto_kdf_hkdf_sha256_extract_init(salt)
state = pysodium.crypto_kdf_hkdf_sha256_extract_update(state, ikm)
self.assertEqual(expected_prk, pysodium.crypto_kdf_hkdf_sha256_extract_final(state))
self.assertEqual(expected_out, pysodium.crypto_kdf_hkdf_sha256_expand(outlen, expected_prk, ctx))

def test_crypto_kx(self):
if not pysodium.sodium_version_check(1, 0, 12): return
client_pk, client_sk = pysodium.crypto_kx_keypair()
Expand Down

0 comments on commit 9d078c4

Please sign in to comment.