mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-10 23:00:30 -08:00
Compare commits
923 Commits
dev/broker
...
dev/karo/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4eea31c5d | ||
|
|
9fd32086ea | ||
|
|
63511465de | ||
|
|
0c960d57bc | ||
|
|
8f276f70a6 | ||
|
|
9580961dd9 | ||
|
|
1a51478e89 | ||
|
|
5b14ef8065 | ||
|
|
a796bdd2e7 | ||
|
|
433ff09c43 | ||
|
|
11c055738e | ||
|
|
0c48cfb91f | ||
|
|
3f0c71d74b | ||
|
|
55ab57a1d0 | ||
|
|
49be83847b | ||
|
|
aa42ba070b | ||
|
|
8bf9ca203e | ||
|
|
8b98d4caca | ||
|
|
9d5996e71c | ||
|
|
f59b63a4d3 | ||
|
|
e3a88d9a5e | ||
|
|
3c6a3a3735 | ||
|
|
f38949615f | ||
|
|
f431301d1e | ||
|
|
771cacb8c8 | ||
|
|
6383231a6a | ||
|
|
4daca9ed56 | ||
|
|
75ff1e8292 | ||
|
|
484af1654a | ||
|
|
9c82424dee | ||
|
|
823e5aca56 | ||
|
|
22bf2e3990 | ||
|
|
f39a43a821 | ||
|
|
bc6fa0d672 | ||
|
|
db797ff11e | ||
|
|
7790d82b51 | ||
|
|
b52c607efc | ||
|
|
d2a85a0d6b | ||
|
|
221c583508 | ||
|
|
14c48cf069 | ||
|
|
6e43a21e74 | ||
|
|
6bfc29ef93 | ||
|
|
39341c0ef8 | ||
|
|
9ee86e01ec | ||
|
|
3721996f2d | ||
|
|
49ccb1ea95 | ||
|
|
baa534f2e2 | ||
|
|
6e62cd7c36 | ||
|
|
a18e793a53 | ||
|
|
48e9dd2a86 | ||
|
|
7d4ae23db9 | ||
|
|
1c85091b6d | ||
|
|
b88d3961ea | ||
|
|
82135cce5c | ||
|
|
879a25ec46 | ||
|
|
098aff91ab | ||
|
|
d5162d7b9a | ||
|
|
8ee0619c08 | ||
|
|
15f2153b1b | ||
|
|
2fc2e073ef | ||
|
|
8f01790d04 | ||
|
|
ad1235c4f8 | ||
|
|
c08c99968f | ||
|
|
3498a6e12c | ||
|
|
ed4ec9d7dd | ||
|
|
e1c19a083f | ||
|
|
32a4051281 | ||
|
|
9e6a9a7a4a | ||
|
|
c8a724a8d0 | ||
|
|
dffd0b33fe | ||
|
|
ba1c6a177e | ||
|
|
6577d1731c | ||
|
|
18b6dae902 | ||
|
|
651d59cc8c | ||
|
|
3e4e67b1e3 | ||
|
|
e3fe9bdb95 | ||
|
|
66c71c7990 | ||
|
|
7f9cc510a1 | ||
|
|
9d37c63da7 | ||
|
|
dddadb67b8 | ||
|
|
b5ef5842d9 | ||
|
|
c3e8297fa0 | ||
|
|
223fbd551f | ||
|
|
5c909b4ab9 | ||
|
|
6b7f620566 | ||
|
|
916a9ebb71 | ||
|
|
3e33e8ffa1 | ||
|
|
5b8760cb46 | ||
|
|
2e17779447 | ||
|
|
75763bf27d | ||
|
|
83ad7652bc | ||
|
|
76a8a39560 | ||
|
|
de72e4a2a1 | ||
|
|
f0467ea28b | ||
|
|
15a4dfa03b | ||
|
|
1a8713a26f | ||
|
|
2694f4a86b | ||
|
|
b905c0aa06 | ||
|
|
4f2519fb9c | ||
|
|
72e6542958 | ||
|
|
1e6e17e094 | ||
|
|
8e7fd174e8 | ||
|
|
7908359eab | ||
|
|
15ae4b4ae5 | ||
|
|
b5107c77d8 | ||
|
|
335584b187 | ||
|
|
3c0e167347 | ||
|
|
6f6fdef542 | ||
|
|
c839126e29 | ||
|
|
a1698f36a6 | ||
|
|
2d6550da0f | ||
|
|
bae336d633 | ||
|
|
6c929f7ddc | ||
|
|
41eb620751 | ||
|
|
8561aaf137 | ||
|
|
f0ee7a33c9 | ||
|
|
1d4a70f863 | ||
|
|
f4e8e4314b | ||
|
|
1b9be7519b | ||
|
|
c689f8e78a | ||
|
|
edcbf290fc | ||
|
|
31a5dbe420 | ||
|
|
a85f9b8e63 | ||
|
|
21ea526435 | ||
|
|
35e956e340 | ||
|
|
3371d7f00f | ||
|
|
3f2a9bb96b | ||
|
|
8dfa67a2dd | ||
|
|
f31d635df8 | ||
|
|
75702dfc03 | ||
|
|
3af479a27e | ||
|
|
e76e5b253f | ||
|
|
0d944afbd8 | ||
|
|
8d81be56f3 | ||
|
|
16b3914c46 | ||
|
|
ae060f7cfb | ||
|
|
afa6212264 | ||
|
|
3c744c253b | ||
|
|
53e6553c8b | ||
|
|
4cd2cdfcff | ||
|
|
3e03e47935 | ||
|
|
7003671cde | ||
|
|
91fc50c1e1 | ||
|
|
b1a7d94295 | ||
|
|
48b7bb2f14 | ||
|
|
77e3682820 | ||
|
|
8bad02bcda | ||
|
|
864407f90b | ||
|
|
4deee59e90 | ||
|
|
c82ed332f6 | ||
|
|
5ced547a07 | ||
|
|
bdaedc4e2a | ||
|
|
4e77e67f10 | ||
|
|
f33c3a6928 | ||
|
|
348650d507 | ||
|
|
c318cf7bac | ||
|
|
d9a6430472 | ||
|
|
9656fa7025 | ||
|
|
53ddad30f1 | ||
|
|
7e8e502bca | ||
|
|
d81649c1d1 | ||
|
|
da642186f2 | ||
|
|
ad6d053015 | ||
|
|
240a1f923d | ||
|
|
a538dee0c3 | ||
|
|
08ea045325 | ||
|
|
6b61823255 | ||
|
|
96ac01ff2e | ||
|
|
811c1746c1 | ||
|
|
91707cc430 | ||
|
|
73df0ceca7 | ||
|
|
9cc7a58ee7 | ||
|
|
5106ffd549 | ||
|
|
7fc6fd2f52 | ||
|
|
77b50b70b1 | ||
|
|
cf061bd0f5 | ||
|
|
196d459a2b | ||
|
|
5097d9fce1 | ||
|
|
cdf6e8369f | ||
|
|
d5eb996423 | ||
|
|
6c49f38e29 | ||
|
|
e021b9f11d | ||
|
|
49f384c380 | ||
|
|
7e590dd30e | ||
|
|
d98815fa7f | ||
|
|
dd105a4491 | ||
|
|
64ff326e14 | ||
|
|
37e71a4051 | ||
|
|
e90bc1b636 | ||
|
|
bbd7e7bb72 | ||
|
|
3d724f04d4 | ||
|
|
db9d0b642b | ||
|
|
50501f37fd | ||
|
|
39f99fbfea | ||
|
|
3ea1a824cc | ||
|
|
d496490916 | ||
|
|
740489544d | ||
|
|
22b980a61f | ||
|
|
a45812b2cd | ||
|
|
1025de2c64 | ||
|
|
b8e9519e26 | ||
|
|
c3def9744f | ||
|
|
e3d3584adb | ||
|
|
a1982e0245 | ||
|
|
4896cd6130 | ||
|
|
9aab9d2d2a | ||
|
|
108ca440fe | ||
|
|
03e408b7c2 | ||
|
|
67f387a190 | ||
|
|
745c3962bb | ||
|
|
f6971aa5ad | ||
|
|
b46cd636d2 | ||
|
|
f22f4aad7d | ||
|
|
a83589d76a | ||
|
|
508d46f2bc | ||
|
|
3fc3083a54 | ||
|
|
faa45a8540 | ||
|
|
77632d0725 | ||
|
|
7218b0a3f4 | ||
|
|
4266cbfb72 | ||
|
|
070d299329 | ||
|
|
15699710a0 | ||
|
|
ae418ffba7 | ||
|
|
e3f7773bac | ||
|
|
9ab754eb0b | ||
|
|
b055457d01 | ||
|
|
b3403e7120 | ||
|
|
abd5210ae4 | ||
|
|
03464e1be7 | ||
|
|
54fc904c15 | ||
|
|
ceff8b711a | ||
|
|
c84bbed3bd | ||
|
|
d453002230 | ||
|
|
e81612d2e3 | ||
|
|
d558bdb633 | ||
|
|
e8fb7206fc | ||
|
|
b47d3a9deb | ||
|
|
f7fb09bc44 | ||
|
|
db6530ef77 | ||
|
|
8f519b042d | ||
|
|
954162b61f | ||
|
|
c65abe7bd9 | ||
|
|
80885d81d7 | ||
|
|
d023108d3b | ||
|
|
417df7aa7f | ||
|
|
9dd00e04c1 | ||
|
|
1a8e220aa8 | ||
|
|
de0022f092 | ||
|
|
dbb891a2ed | ||
|
|
531ae0ef70 | ||
|
|
8bb54b9cca | ||
|
|
7566eadef8 | ||
|
|
ebf6403ea7 | ||
|
|
62d408eade | ||
|
|
d1cf6af531 | ||
|
|
5e6c85d73d | ||
|
|
3205f8c572 | ||
|
|
b21a95dbbd | ||
|
|
006946442a | ||
|
|
33901d598a | ||
|
|
944be10bd2 | ||
|
|
23cf60c7ec | ||
|
|
6f71767529 | ||
|
|
38f371e3d7 | ||
|
|
2dba9205e7 | ||
|
|
30c3de3f87 | ||
|
|
b16619b1d3 | ||
|
|
576ad5f6d0 | ||
|
|
6494518460 | ||
|
|
185e92108e | ||
|
|
253243a8c8 | ||
|
|
075d9ffff3 | ||
|
|
01a1408044 | ||
|
|
b84e0beae8 | ||
|
|
949a3e4d23 | ||
|
|
d61b137761 | ||
|
|
a1f41953b7 | ||
|
|
46ebb6f46c | ||
|
|
32ae8f7051 | ||
|
|
b94ddd980d | ||
|
|
44e46895aa | ||
|
|
2ddd1488b3 | ||
|
|
c9aad280b2 | ||
|
|
d7398d9bcf | ||
|
|
6d25c13fd1 | ||
|
|
2d2d109246 | ||
|
|
30e158f594 | ||
|
|
cf74584f51 | ||
|
|
793cfd227f | ||
|
|
54c8e91db4 | ||
|
|
1b0179e751 | ||
|
|
760ecdc457 | ||
|
|
6a9bbddde3 | ||
|
|
530f81b9d5 | ||
|
|
b96df1588c | ||
|
|
5a2555a327 | ||
|
|
ac3f21c4bd | ||
|
|
b36d30d89d | ||
|
|
62fe529d36 | ||
|
|
76d01ffaf9 | ||
|
|
576b17cd9c | ||
|
|
cbc1bb4be2 | ||
|
|
c8a084157e | ||
|
|
09f1353dcc | ||
|
|
43225c1fe8 | ||
|
|
8e41cfc0b4 | ||
|
|
69538622b4 | ||
|
|
45a7c17cdd | ||
|
|
b8ecdab8dc | ||
|
|
af9d83b472 | ||
|
|
f81e329a11 | ||
|
|
5e2c72ef99 | ||
|
|
88e7d1d1cb | ||
|
|
43a930d3f7 | ||
|
|
b5f6d07650 | ||
|
|
be3c3d3d61 | ||
|
|
fe60cea959 | ||
|
|
441988cf43 | ||
|
|
b40b7f4f2f | ||
|
|
da76d88170 | ||
|
|
e35955f99c | ||
|
|
87587399ed | ||
|
|
9fdba31b32 | ||
|
|
0bfe47e5b8 | ||
|
|
771dce3ac7 | ||
|
|
436c6e6f87 | ||
|
|
f093406c34 | ||
|
|
eadf70ee38 | ||
|
|
7ac0883970 | ||
|
|
b1658b83a0 | ||
|
|
27650e95a7 | ||
|
|
6ab4e1152c | ||
|
|
2c64da23f1 | ||
|
|
03cc609a1e | ||
|
|
3effcb313e | ||
|
|
fded3b2e79 | ||
|
|
1471bb6a9f | ||
|
|
7edf84bd4a | ||
|
|
5187e50bb7 | ||
|
|
fd5806ba55 | ||
|
|
8e50d38b38 | ||
|
|
377f2f40d2 | ||
|
|
9bae080c4d | ||
|
|
3392da5163 | ||
|
|
3109cf1ffc | ||
|
|
d2539e445f | ||
|
|
6dc58cc6c1 | ||
|
|
e3d16966c9 | ||
|
|
a5e6af4b49 | ||
|
|
24a71977f0 | ||
|
|
5f0ac579d7 | ||
|
|
4df994b5f0 | ||
|
|
e4e0a9e661 | ||
|
|
742e037936 | ||
|
|
b5848af799 | ||
|
|
4982e40084 | ||
|
|
c1ae3268c6 | ||
|
|
524ec68f3f | ||
|
|
184603aa2c | ||
|
|
ec6706ffeb | ||
|
|
7571670e71 | ||
|
|
0d7dd99d96 | ||
|
|
c78a9cb777 | ||
|
|
dd0db53e8b | ||
|
|
422acf9891 | ||
|
|
877c15a018 | ||
|
|
55d7f8b1c1 | ||
|
|
199ff63a06 | ||
|
|
47b556e317 | ||
|
|
f87e2cb31b | ||
|
|
58e1c8fbff | ||
|
|
c89c7d7acf | ||
|
|
a5b876f119 | ||
|
|
c2f50f47b3 | ||
|
|
53168dc62d | ||
|
|
2cfe703118 | ||
|
|
a2d7c3aaa6 | ||
|
|
1aa111570e | ||
|
|
a91d61f9f0 | ||
|
|
ff7827c24e | ||
|
|
255e377d29 | ||
|
|
50505d81cc | ||
|
|
10484cc6d4 | ||
|
|
d27e602f43 | ||
|
|
73f6b33dbb | ||
|
|
a279dfc0b1 | ||
|
|
caf2f6bfec | ||
|
|
d398ad369e | ||
|
|
00696321ff | ||
|
|
d807a1bca7 | ||
|
|
4daf97b2ee | ||
|
|
b394e302ab | ||
|
|
198bc2d5f2 | ||
|
|
fc2f535eae | ||
|
|
302e249f08 | ||
|
|
d8fe3eba5f | ||
|
|
35519e7baa | ||
|
|
78af5d1dc4 | ||
|
|
61b8b28e86 | ||
|
|
26f77924f8 | ||
|
|
2e0e2cfa0c | ||
|
|
9cc860fdeb | ||
|
|
a537eb3e1b | ||
|
|
ea233bf137 | ||
|
|
db8796ab40 | ||
|
|
0353c82729 | ||
|
|
ae3fbde0a3 | ||
|
|
51d4dede15 | ||
|
|
4725a2d628 | ||
|
|
a6bac74d48 | ||
|
|
b9a34f4238 | ||
|
|
46e855b266 | ||
|
|
c0b91fd729 | ||
|
|
97dff8453d | ||
|
|
a3d4686104 | ||
|
|
cee0678817 | ||
|
|
a996f194c7 | ||
|
|
447be89414 | ||
|
|
ef4f550abc | ||
|
|
4737cd2b2a | ||
|
|
9336794e4d | ||
|
|
096bac6ee5 | ||
|
|
161826979a | ||
|
|
c435b772d2 | ||
|
|
8805ef7c38 | ||
|
|
cca02dc8d1 | ||
|
|
d4350195eb | ||
|
|
1c5e4ecf95 | ||
|
|
b15947b815 | ||
|
|
cacbf8535c | ||
|
|
f6d9da4a18 | ||
|
|
68f73e264d | ||
|
|
d5f68dcbd2 | ||
|
|
96581ed118 | ||
|
|
553b058759 | ||
|
|
85286c146f | ||
|
|
0f58b36c5b | ||
|
|
737781c8bc | ||
|
|
4ea1c76b81 | ||
|
|
5251721bcf | ||
|
|
a789f801ab | ||
|
|
be06f8adec | ||
|
|
03d3c70e2e | ||
|
|
94ba99d89b | ||
|
|
667a994253 | ||
|
|
9561ea4a47 | ||
|
|
fb641f8568 | ||
|
|
6e16956bc7 | ||
|
|
eeb738b649 | ||
|
|
2d20ad6335 | ||
|
|
df3d1821c8 | ||
|
|
6048ebd3d9 | ||
|
|
cd7558594f | ||
|
|
022cdc4ffa | ||
|
|
06d4e289a5 | ||
|
|
f9dce3fc9a | ||
|
|
d9f3c8fb96 | ||
|
|
0ea9f1061e | ||
|
|
737f0bc9f9 | ||
|
|
32ebd18107 | ||
|
|
f04cff6d57 | ||
|
|
2c1a0a7451 | ||
|
|
74fdb44680 | ||
|
|
c3adbb7cf3 | ||
|
|
fa583ec6ae | ||
|
|
aa76db1e1c | ||
|
|
c5699b5259 | ||
|
|
d3c52fdf64 | ||
|
|
b18f05ae19 | ||
|
|
d8839ba341 | ||
|
|
7022a93378 | ||
|
|
c9da9b8591 | ||
|
|
b483612cb7 | ||
|
|
a30805f8a0 | ||
|
|
a9b0a90ab5 | ||
|
|
2bc138e614 | ||
|
|
f97781039f | ||
|
|
5eda161cf2 | ||
|
|
a473fe6d9b | ||
|
|
e2c46f1ff0 | ||
|
|
c8b804b39d | ||
|
|
e56798b04c | ||
|
|
b76d18e3c8 | ||
|
|
a9792c3143 | ||
|
|
cb2c1c12ee | ||
|
|
08514d69e5 | ||
|
|
baf2d68070 | ||
|
|
cc7f7a4b4d | ||
|
|
5b701631b5 | ||
|
|
402158b706 | ||
|
|
e95636bf70 | ||
|
|
744e2bcf3e | ||
|
|
8c82ca18fb | ||
|
|
208e79c3a7 | ||
|
|
6ee023c9e9 | ||
|
|
6f75d34934 | ||
|
|
6b364a35dc | ||
|
|
2b6d10f0aa | ||
|
|
cb380b89d1 | ||
|
|
f703933e7f | ||
|
|
d02a5d2eb7 | ||
|
|
c7273e6f88 | ||
|
|
85eca49a5b | ||
|
|
9943f1336b | ||
|
|
bb2a0732cc | ||
|
|
1275b992a0 | ||
|
|
196767964f | ||
|
|
d4e9770fe6 | ||
|
|
8e2f6991d1 | ||
|
|
af0db88939 | ||
|
|
6601742903 | ||
|
|
9436281350 | ||
|
|
f3399907b9 | ||
|
|
0cea8c5eff | ||
|
|
5b3f4da23e | ||
|
|
c13badb697 | ||
|
|
cc7757a0db | ||
|
|
d267916445 | ||
|
|
03bc89a582 | ||
|
|
19b31bcdf0 | ||
|
|
939d216027 | ||
|
|
05fbaff2dc | ||
|
|
1d1c0e9da7 | ||
|
|
e19b724673 | ||
|
|
f879ad5020 | ||
|
|
29e7087cb5 | ||
|
|
637a08d222 | ||
|
|
6416c247f4 | ||
|
|
4b3b7e41e4 | ||
|
|
325fb915f0 | ||
|
|
43cb0c09c5 | ||
|
|
0836a2eb28 | ||
|
|
ca7df013d5 | ||
|
|
1209d68718 | ||
|
|
8806494899 | ||
|
|
582d27351a | ||
|
|
61136d79eb | ||
|
|
71bd406201 | ||
|
|
ce63cf534a | ||
|
|
d3ff19bdb9 | ||
|
|
3b6d0822d6 | ||
|
|
533afea129 | ||
|
|
da5b281b96 | ||
|
|
b9e873e534 | ||
|
|
a3b339b180 | ||
|
|
b4347c1382 | ||
|
|
0745019e10 | ||
|
|
2369006342 | ||
|
|
0fa6176d06 | ||
|
|
22bdeaf8f1 | ||
|
|
5731272844 | ||
|
|
bc7cef9de0 | ||
|
|
4cdcc35c3e | ||
|
|
a8f1292cbf | ||
|
|
ae5c5ed2b4 | ||
|
|
c483452a6a | ||
|
|
4ce331d299 | ||
|
|
d81eb7e2ed | ||
|
|
61043500ba | ||
|
|
9c4752559d | ||
|
|
6aec7acdb8 | ||
|
|
337cc1b4b4 | ||
|
|
387a266a49 | ||
|
|
179970b905 | ||
|
|
8b769e04c1 | ||
|
|
810bdf5519 | ||
|
|
d3a666bea0 | ||
|
|
2b8f780584 | ||
|
|
6aea3c0c1f | ||
|
|
e4fdfcae08 | ||
|
|
48e629fff7 | ||
|
|
6321bb36fc | ||
|
|
2f9ff487ba | ||
|
|
c0c06cd1dc | ||
|
|
e9772effa6 | ||
|
|
cf68f15674 | ||
|
|
dd5d45cdc9 | ||
|
|
17a6aed8a6 | ||
|
|
3f9926e353 | ||
|
|
f4ab2ac891 | ||
|
|
de51c1005f | ||
|
|
1e2cd589b1 | ||
|
|
02bc485d97 | ||
|
|
3ae52b9824 | ||
|
|
cbf361206b | ||
|
|
398da99df2 | ||
|
|
acfbb67abe | ||
|
|
c407b8b006 | ||
|
|
bc7213d8c0 | ||
|
|
69e68aad2c | ||
|
|
9b07f5803b | ||
|
|
5ce572b739 | ||
|
|
d9f8fa0092 | ||
|
|
a5208795f6 | ||
|
|
0959148305 | ||
|
|
f2bc3a8b64 | ||
|
|
06529df2c0 | ||
|
|
128c77f77a | ||
|
|
501cc9bb05 | ||
|
|
9ad5277a90 | ||
|
|
0cbcaeaf98 | ||
|
|
687ef3f6f8 | ||
|
|
b0706354d3 | ||
|
|
c1e86daec8 | ||
|
|
18a286e688 | ||
|
|
cb92313391 | ||
|
|
5cd30b4c13 | ||
|
|
76d8d38744 | ||
|
|
f63f0bbc2e | ||
|
|
4a449e6502 | ||
|
|
1e6d2df004 | ||
|
|
3fa9aadda2 | ||
|
|
0c79a4ce95 | ||
|
|
036960b5b1 | ||
|
|
e7258849cb | ||
|
|
8c88f68990 | ||
|
|
cf20536576 | ||
|
|
72e18e3ec2 | ||
|
|
6040156a0e | ||
|
|
d3b318b413 | ||
|
|
3a49345138 | ||
|
|
4ec7813259 | ||
|
|
db31da14d3 | ||
|
|
4c20efc8a8 | ||
|
|
c81d484294 | ||
|
|
cc578169d6 | ||
|
|
91527702f1 | ||
|
|
0179f1c673 | ||
|
|
2238919657 | ||
|
|
d913e19883 | ||
|
|
1555d0897b | ||
|
|
abdbf8f3da | ||
|
|
9f78531979 | ||
|
|
624d8d2f44 | ||
|
|
9bbf9433e6 | ||
|
|
77760d71df | ||
|
|
53e560191f | ||
|
|
93cd266c68 | ||
|
|
594f894206 | ||
|
|
a831e01a5c | ||
|
|
0884641d64 | ||
|
|
ae85d0ed2b | ||
|
|
163f66f20e | ||
|
|
3caff91515 | ||
|
|
24eebe29a1 | ||
|
|
1d2fa7d038 | ||
|
|
edf1e774c1 | ||
|
|
7a31b57227 | ||
|
|
d5a8c85abe | ||
|
|
48f7ff93e3 | ||
|
|
5f6c36e773 | ||
|
|
7b3b7612cf | ||
|
|
c1704b1464 | ||
|
|
2785aaf783 | ||
|
|
15002a74cc | ||
|
|
0fe2d9825b | ||
|
|
ab805dae75 | ||
|
|
08653c3338 | ||
|
|
520c8c6eaa | ||
|
|
258efe408c | ||
|
|
fd0f35b279 | ||
|
|
8808ed5dbc | ||
|
|
6fc45cab53 | ||
|
|
1f7196e473 | ||
|
|
c359b87d0c | ||
|
|
355b48169b | ||
|
|
274d245bed | ||
|
|
065b0fcc8a | ||
|
|
191fb10663 | ||
|
|
3faa84117f | ||
|
|
fda75a0184 | ||
|
|
96b1f6c0d3 | ||
|
|
fb73c68626 | ||
|
|
42b0e23695 | ||
|
|
c58f832727 | ||
|
|
7b6a9eebc1 | ||
|
|
4554dc4bb3 | ||
|
|
465c6beaab | ||
|
|
1853e0a3c0 | ||
|
|
245d4d1a0f | ||
|
|
d5d15cd9bc | ||
|
|
9fd3df67ed | ||
|
|
6d47169a5c | ||
|
|
4bcd38a4ea | ||
|
|
730a03957a | ||
|
|
ea071f5363 | ||
|
|
3063d3e4c2 | ||
|
|
1bf0eed90a | ||
|
|
138e6b6553 | ||
|
|
2dde0a2b47 | ||
|
|
3cc3b6009f | ||
|
|
1ab457ed37 | ||
|
|
c9c266fe7c | ||
|
|
8d3c8790fe | ||
|
|
648a94ead8 | ||
|
|
54ac5eecdb | ||
|
|
40c5bbd167 | ||
|
|
a4b8fc2226 | ||
|
|
37f7b3e4e9 | ||
|
|
deafc1c1af | ||
|
|
6bbe85a57b | ||
|
|
e70c5b33a8 | ||
|
|
25fdfef4d0 | ||
|
|
6ab8fafe59 | ||
|
|
c1aacf76b8 | ||
|
|
1bcaf5781f | ||
|
|
de60e5f8f0 | ||
|
|
b50ddda151 | ||
|
|
7282fba3b3 | ||
|
|
0cca389f10 | ||
|
|
8a08d49215 | ||
|
|
8637bc7884 | ||
|
|
4412c2bdd1 | ||
|
|
ecc815dd8e | ||
|
|
b7d7c03e35 | ||
|
|
f6320c3c35 | ||
|
|
19f7905bc9 | ||
|
|
9b5b7ee620 | ||
|
|
4fdd271de7 | ||
|
|
860e65965a | ||
|
|
87144233da | ||
|
|
d0a6e99a1f | ||
|
|
79b634fadf | ||
|
|
99ac3c0902 | ||
|
|
010c14dadf | ||
|
|
45b6132312 | ||
|
|
77f9fd38f3 | ||
|
|
775ed86adc | ||
|
|
40377dce1f | ||
|
|
19293471e8 | ||
|
|
cc5877dd83 | ||
|
|
ebb591aa6f | ||
|
|
07146d9914 | ||
|
|
cd04dbc4eb | ||
|
|
cc22165dc4 | ||
|
|
8496571765 | ||
|
|
ee3a1f580e | ||
|
|
89584645c3 | ||
|
|
3286e49370 | ||
|
|
100d7b6e1c | ||
|
|
921b2bfc39 | ||
|
|
a18658847c | ||
|
|
bdad414c90 | ||
|
|
7c54a37618 | ||
|
|
7a4f700186 | ||
|
|
f535a31cd7 | ||
|
|
ac2aaa5fbd | ||
|
|
e472fa1fcd | ||
|
|
526c930119 | ||
|
|
5f8b00d045 | ||
|
|
b46fca99cb | ||
|
|
70c5ec2c29 | ||
|
|
0e059af5da | ||
|
|
99754f326e | ||
|
|
fd397b9ea0 | ||
|
|
e92fa552e3 | ||
|
|
c438d5a99d | ||
|
|
d4eef998f5 | ||
|
|
c1abfbfd14 | ||
|
|
ae7577c641 | ||
|
|
f07f598e44 | ||
|
|
988f66cf2b | ||
|
|
06969c406d | ||
|
|
b5215aecba | ||
|
|
3e32bbad7c | ||
|
|
650110a04f | ||
|
|
ee669823de | ||
|
|
40940ca1df | ||
|
|
b77eccffc0 | ||
|
|
e17d8cd559 | ||
|
|
c72e8bcda1 | ||
|
|
2bac991305 | ||
|
|
e6d114c557 | ||
|
|
29efbba97a | ||
|
|
3fb1220262 | ||
|
|
1ccf92c538 | ||
|
|
4bb3153761 | ||
|
|
a8ed0e8c66 | ||
|
|
ad6405f865 | ||
|
|
761d5730af | ||
|
|
b45b7bc7f5 | ||
|
|
77a985dc02 | ||
|
|
21e693a9da | ||
|
|
be91b3049c | ||
|
|
4dc24f745c | ||
|
|
61a1cc3825 | ||
|
|
2e01d1df46 | ||
|
|
2c6411a2b1 | ||
|
|
96b12ac261 | ||
|
|
3e734e0d57 | ||
|
|
c9e296794b | ||
|
|
bc6bff499d | ||
|
|
de905056fc | ||
|
|
4e8344660e | ||
|
|
a581f7dfa7 | ||
|
|
bd6a6e5dce | ||
|
|
e0496c12c6 | ||
|
|
f4116f2c20 | ||
|
|
8099bc4bdd | ||
|
|
39d174c605 | ||
|
|
0257aa9e15 | ||
|
|
3299b2bdb4 | ||
|
|
f43b018511 | ||
|
|
0f884b79fa | ||
|
|
ab83d3fae6 | ||
|
|
cc7e8dc510 | ||
|
|
c2d0d34c57 | ||
|
|
5d46c93b2b | ||
|
|
e6d7a7232f | ||
|
|
6ba1be6eae | ||
|
|
c194c74e55 | ||
|
|
96de84e68f | ||
|
|
6215bc1514 | ||
|
|
b0a93d6884 | ||
|
|
bba0c874f2 | ||
|
|
a32efb61d1 | ||
|
|
10bdb5f371 | ||
|
|
b07859f6ec | ||
|
|
65df24a98b | ||
|
|
9396784c0f | ||
|
|
8420d953eb | ||
|
|
e7de4848fb | ||
|
|
92824bb5b0 | ||
|
|
8d20e77173 | ||
|
|
15aafe7563 | ||
|
|
b56af8b696 | ||
|
|
a3e91a95df | ||
|
|
4ea51ab123 | ||
|
|
4b849a4fe4 | ||
|
|
16e67269ba | ||
|
|
76d5093a20 | ||
|
|
0e8945db78 | ||
|
|
ffd81b6a72 | ||
|
|
d1d218ac0f | ||
|
|
0edfb625e8 | ||
|
|
16c0080cdc | ||
|
|
b05c4bbe24 | ||
|
|
639c65ef93 | ||
|
|
332c549305 | ||
|
|
ef973e9d7f | ||
|
|
199ecb814b | ||
|
|
40d955a156 | ||
|
|
cd23e9a2d0 | ||
|
|
4d482aaab7 | ||
|
|
3175b7b783 | ||
|
|
baa35af558 | ||
|
|
b2de384fcf | ||
|
|
c69fd889fb | ||
|
|
13a853ff42 | ||
|
|
13df700ef5 | ||
|
|
2e7f34f4b2 | ||
|
|
292b4bbae0 | ||
|
|
c75d222477 | ||
|
|
478fadb80d | ||
|
|
7c1ada4b10 | ||
|
|
4f4e8e1018 | ||
|
|
971e49b894 | ||
|
|
262e32fe35 | ||
|
|
4dab97d84e | ||
|
|
1a5ffdd495 | ||
|
|
fb91688672 | ||
|
|
27ba729c14 | ||
|
|
60235dc6ea | ||
|
|
36c99c020e | ||
|
|
8c469af6b1 | ||
|
|
e96968b8bc | ||
|
|
81487b103d | ||
|
|
8ea253f86b | ||
|
|
fd8f2e4424 | ||
|
|
a996b08279 | ||
|
|
19a0a22b62 | ||
|
|
b51466eaec | ||
|
|
9552d5a46c | ||
|
|
a1d61bb48e | ||
|
|
e38a6b8ed4 | ||
|
|
ec0b5f7fb1 | ||
|
|
0b4699e24a | ||
|
|
d18107b3a9 | ||
|
|
715893e1ac | ||
|
|
92b2f6bc7c | ||
|
|
3498ab2d7b | ||
|
|
efd0ce51cb | ||
|
|
7739020931 | ||
|
|
ecfecbb8f9 | ||
|
|
e8a81102f4 | ||
|
|
591e5226fd | ||
|
|
b336a0d264 | ||
|
|
0b7bec75de | ||
|
|
87bbd1eef7 | ||
|
|
2646dc8398 | ||
|
|
4295ec9d80 | ||
|
|
7cb643b181 | ||
|
|
109d624227 | ||
|
|
b96d195f54 | ||
|
|
775b464496 | ||
|
|
e2cd25c184 | ||
|
|
fdcb488d4b | ||
|
|
a8a596ca7e | ||
|
|
9ced9996d2 | ||
|
|
df683f96b2 | ||
|
|
27a8bdbe7b | ||
|
|
bdabae9c33 | ||
|
|
4d7c030476 | ||
|
|
95f22e98ac | ||
|
|
b0dada7613 | ||
|
|
e54ea1feaa | ||
|
|
0fd09c908b | ||
|
|
36628a46d6 | ||
|
|
2904c90d4b | ||
|
|
f0dbe2bb54 | ||
|
|
e2792272e8 | ||
|
|
1c65e67be2 | ||
|
|
2ae3d6c271 | ||
|
|
96d4f0b545 | ||
|
|
ad947a755c | ||
|
|
35f9c3bf68 | ||
|
|
ff44002b7c | ||
|
|
0ce8304c69 | ||
|
|
5f91feb3a4 | ||
|
|
baebb8632f | ||
|
|
cb97f90581 | ||
|
|
3d13caa37b | ||
|
|
54ecfaddcf |
9
.ci/boot_race/a.toml
Normal file
9
.ci/boot_race/a.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
public_key = "rp-a-public-key"
|
||||
secret_key = "rp-a-secret-key"
|
||||
listen = ["127.0.0.1:9999"]
|
||||
verbosity = "Verbose"
|
||||
|
||||
[[peers]]
|
||||
public_key = "rp-b-public-key"
|
||||
endpoint = "127.0.0.1:9998"
|
||||
key_out = "rp-b-key-out.txt"
|
||||
9
.ci/boot_race/b.toml
Normal file
9
.ci/boot_race/b.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
public_key = "rp-b-public-key"
|
||||
secret_key = "rp-b-secret-key"
|
||||
listen = ["127.0.0.1:9998"]
|
||||
verbosity = "Verbose"
|
||||
|
||||
[[peers]]
|
||||
public_key = "rp-a-public-key"
|
||||
endpoint = "127.0.0.1:9999"
|
||||
key_out = "rp-a-key-out.txt"
|
||||
48
.ci/boot_race/run.sh
Normal file
48
.ci/boot_race/run.sh
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
iterations="$1"
|
||||
sleep_time="$2"
|
||||
config_a="$3"
|
||||
config_b="$4"
|
||||
|
||||
PWD="$(pwd)"
|
||||
EXEC="$PWD/target/release/rosenpass"
|
||||
|
||||
i=0
|
||||
while [ "$i" -ne "$iterations" ]; do
|
||||
echo "=> Iteration $i"
|
||||
|
||||
# flush the PSK files
|
||||
echo "A" >rp-a-key-out.txt
|
||||
echo "B" >rp-b-key-out.txt
|
||||
|
||||
# start the two instances
|
||||
echo "Starting instance A"
|
||||
"$EXEC" exchange-config "$config_a" &
|
||||
PID_A=$!
|
||||
sleep "$sleep_time"
|
||||
echo "Starting instance B"
|
||||
"$EXEC" exchange-config "$config_b" &
|
||||
PID_B=$!
|
||||
|
||||
# give the key exchange some time to complete
|
||||
sleep 3
|
||||
|
||||
# kill the instances
|
||||
kill $PID_A
|
||||
kill $PID_B
|
||||
|
||||
# compare the keys
|
||||
if cmp -s rp-a-key-out.txt rp-b-key-out.txt; then
|
||||
echo "Keys match"
|
||||
else
|
||||
echo "::warning title=Key Exchange Race Condition::The key exchange resulted in different keys. Delay was ${sleep_time}s."
|
||||
# TODO: set this to 1 when the race condition is fixed
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# give the instances some time to shut down
|
||||
sleep 2
|
||||
|
||||
i=$((i + 1))
|
||||
done
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env nu
|
||||
|
||||
use log *
|
||||
use std log
|
||||
|
||||
# cd to git root
|
||||
cd (git rev-parse --show-toplevel)
|
||||
@@ -32,9 +32,9 @@ let systems_map = {
|
||||
# aarch64-darwin
|
||||
# aarch64-linux
|
||||
|
||||
i686-linux: ubuntu-latest,
|
||||
i686-linux: ubicloud-standard-2-ubuntu-2204,
|
||||
x86_64-darwin: macos-13,
|
||||
x86_64-linux: ubuntu-latest
|
||||
x86_64-linux: ubicloud-standard-2-ubuntu-2204
|
||||
}
|
||||
|
||||
let targets = (get-attr-names ".#packages"
|
||||
@@ -61,14 +61,13 @@ mut release_workflow = {
|
||||
|
||||
let runner_setup = [
|
||||
{
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
}
|
||||
{
|
||||
uses: "cachix/install-nix-action@v22",
|
||||
with: { nix_path: "nixpkgs=channel:nixos-unstable" }
|
||||
uses: "cachix/install-nix-action@v30",
|
||||
}
|
||||
{
|
||||
uses: "cachix/cachix-action@v12",
|
||||
uses: "cachix/cachix-action@v15",
|
||||
with: {
|
||||
name: rosenpass,
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
@@ -116,6 +115,7 @@ for system in ($targets | columns) {
|
||||
} }
|
||||
| filter {|it| $it.needed}
|
||||
| each {|it| job-id $system $it.name}
|
||||
| sort
|
||||
)
|
||||
|
||||
mut new_job = {
|
||||
@@ -153,7 +153,7 @@ for system in ($targets | columns) {
|
||||
}
|
||||
{
|
||||
name: Release,
|
||||
uses: "softprops/action-gh-release@v1",
|
||||
uses: "softprops/action-gh-release@v2",
|
||||
with: {
|
||||
draft: "${{ contains(github.ref_name, 'rc') }}",
|
||||
prerelease: "${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}",
|
||||
@@ -181,7 +181,7 @@ $cachix_workflow.jobs = ($cachix_workflow.jobs | insert $"($system)---whitepaper
|
||||
}
|
||||
{
|
||||
name: "Deploy PDF artifacts",
|
||||
uses: "peaceiris/actions-gh-pages@v3",
|
||||
uses: "peaceiris/actions-gh-pages@v4",
|
||||
with: {
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}",
|
||||
publish_dir: result/,
|
||||
@@ -197,4 +197,4 @@ $cachix_workflow | to yaml | save --force .github/workflows/nix.yaml
|
||||
$release_workflow | to yaml | save --force .github/workflows/release.yaml
|
||||
|
||||
log info "prettify generated yaml"
|
||||
prettier -w .github/workflows/
|
||||
prettier -w .github/workflows/
|
||||
|
||||
33
.ci/run-regression.sh
Executable file
33
.ci/run-regression.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
iterations="$1"
|
||||
sleep_time="$2"
|
||||
|
||||
PWD="$(pwd)"
|
||||
EXEC="$PWD/target/release/rosenpass"
|
||||
LOGS="$PWD/output/logs"
|
||||
|
||||
mkdir -p "$LOGS"
|
||||
|
||||
run_command() {
|
||||
local file=$1
|
||||
local log_file="$2"
|
||||
("$EXEC" exchange-config "$file" 2>&1 | tee -a "$log_file") &
|
||||
echo $!
|
||||
}
|
||||
|
||||
pids=()
|
||||
|
||||
(cd output/dut && run_command "configs/dut-$iterations.toml" "$LOGS/dut.log")
|
||||
for (( x=0; x<iterations; x++ )); do
|
||||
(cd output/ate && run_command "configs/ate-$x.toml" "$LOGS/ate-$x.log") & pids+=($!)
|
||||
done
|
||||
|
||||
sleep "$sleep_time"
|
||||
|
||||
lsof -i :9999 | awk 'NR!=1 {print $2}' | xargs kill
|
||||
|
||||
for (( x=0; x<iterations; x++ )); do
|
||||
port=$((x + 50000))
|
||||
lsof -i :$port | awk 'NR!=1 {print $2}' | xargs kill
|
||||
done
|
||||
1
.devcontainer/Dockerfile
Normal file
1
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM ghcr.io/xtruder/nix-devcontainer:v1
|
||||
33
.devcontainer/devcontainer.json
Normal file
33
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,33 @@
|
||||
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/docker-existing-dockerfile
|
||||
{
|
||||
"name": "devcontainer-project",
|
||||
"dockerFile": "Dockerfile",
|
||||
"context": "${localWorkspaceFolder}",
|
||||
"build": {
|
||||
"args": {
|
||||
"USER_UID": "${localEnv:USER_UID}",
|
||||
"USER_GID": "${localEnv:USER_GID}"
|
||||
}
|
||||
},
|
||||
|
||||
// run arguments passed to docker
|
||||
"runArgs": ["--security-opt", "label=disable"],
|
||||
|
||||
// disable command overriding and updating remote user ID
|
||||
"overrideCommand": false,
|
||||
"userEnvProbe": "loginShell",
|
||||
"updateRemoteUserUID": false,
|
||||
|
||||
// build development environment on creation, make sure you already have shell.nix
|
||||
"onCreateCommand": "nix develop",
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": ["rust-lang.rust-analyzer", "tamasfe.even-better-toml"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
examples/
|
||||
target/
|
||||
flake.*
|
||||
.ci
|
||||
.direnv
|
||||
.git
|
||||
.github
|
||||
1
.dockerignore
Symbolic link
1
.dockerignore
Symbolic link
@@ -0,0 +1 @@
|
||||
.gitignore
|
||||
14
.github/codecov.yml
vendored
Normal file
14
.github/codecov.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
codecov:
|
||||
branch: main
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# basic
|
||||
target: auto #default
|
||||
threshold: 5
|
||||
base: auto
|
||||
if_ci_failed: error #success, failure, error, ignore
|
||||
informational: false
|
||||
only_pulls: true
|
||||
patch: off
|
||||
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
103
.github/workflows/bench-primitives.yml
vendored
Normal file
103
.github/workflows/bench-primitives.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
name: rosenpass-ciphers - primitives - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
#pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
prim-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubicloud-standard-2
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks (using Nix as shell)
|
||||
working-directory: ciphers
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -F bench --bench primitives --verbose -- --output-format bencher | tee ../bench-primitives.txt
|
||||
|
||||
- name: Extract benchmarks
|
||||
uses: cryspen/benchmark-data-extract-transform@v2
|
||||
with:
|
||||
name: rosenpass-ciphers primitives benchmarks
|
||||
tool: "cargo"
|
||||
os: ${{ matrix.system }}
|
||||
output-file-path: bench-primitives.txt
|
||||
data-out-path: bench-primitives-os.json
|
||||
|
||||
- name: Fix up 'os' label in benchmark data
|
||||
run: jq 'map(with_entries(.key |= if . == "os" then "operating system" else . end))' <bench-primitives-os.json >bench-primitives.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Crypto Primitives Benchmarks
|
||||
group-by: "operating system,primitive,algorithm"
|
||||
schema: "operating system,primitive,algorithm,implementation,operation,length"
|
||||
input-data-path: bench-primitives.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-primitives-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [prim-benchmark]
|
||||
runs-on: ubicloud-standard-2
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
90
.github/workflows/bench-protocol.yml
vendored
Normal file
90
.github/workflows/bench-protocol.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: rosenpass - protocol - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
#pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
proto-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubicloud-standard-2
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -p rosenpass --bench trace_handshake -F trace_bench --verbose >bench-protocol.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Protocol Benchmarks
|
||||
group-by: "operating system,architecture,protocol version,run time"
|
||||
schema: "operating system,architecture,protocol version,run time,name"
|
||||
input-data-path: bench-protocol.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-protocol-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [proto-benchmark]
|
||||
runs-on: ubicloud-standard-2
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
63
.github/workflows/dependent-issues.yml
vendored
Normal file
63
.github/workflows/dependent-issues.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Dependent Issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- closed
|
||||
- reopened
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- closed
|
||||
- reopened
|
||||
# Makes sure we always add status check for PRs. Useful only if
|
||||
# this action is required to pass before merging. Otherwise, it
|
||||
# can be removed.
|
||||
- synchronize
|
||||
|
||||
# Schedule a daily check. Useful if you reference cross-repository
|
||||
# issues or pull requests. Otherwise, it can be removed.
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
check:
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: z0al/dependent-issues@v1
|
||||
env:
|
||||
# (Required) The token to use to make API calls to GitHub.
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# (Optional) The token to use to make API calls to GitHub for remote repos.
|
||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||
|
||||
with:
|
||||
# (Optional) The label to use to mark dependent issues
|
||||
label: dependent
|
||||
|
||||
# (Optional) Enable checking for dependencies in issues.
|
||||
# Enable by setting the value to "on". Default "off"
|
||||
check_issues: off
|
||||
|
||||
# (Optional) Ignore dependabot PRs.
|
||||
# Enable by setting the value to "on". Default "off"
|
||||
ignore_dependabot: off
|
||||
|
||||
# (Optional) A comma-separated list of keywords. Default
|
||||
# "depends on, blocked by"
|
||||
keywords: depends on, blocked by
|
||||
|
||||
# (Optional) A custom comment body. It supports `{{ dependencies }}` token.
|
||||
comment: >
|
||||
This PR/issue depends on:
|
||||
|
||||
{{ dependencies }}
|
||||
|
||||
By **[Dependent Issues](https://github.com/z0al/dependent-issues)** (🤖). Happy coding!
|
||||
4
.github/workflows/doc-upload.yml
vendored
4
.github/workflows/doc-upload.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Clone rosenpass-website repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: rosenpass/rosenpass-website
|
||||
ref: main
|
||||
|
||||
288
.github/workflows/docker.yaml
vendored
Normal file
288
.github/workflows/docker.yaml
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
name: Build Docker Images
|
||||
|
||||
# Run this job on all non-pull-request events,
|
||||
# or if Docker-related files are changed in a pull request.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "docker/Dockerfile"
|
||||
- ".github/workflows/docker.yaml"
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
# --------------------------------
|
||||
# 1. BUILD & TEST
|
||||
# --------------------------------
|
||||
build-and-test-rp:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build (no push) and Load
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
# no pushing here, so we can test locally
|
||||
push: false
|
||||
# load the built image into the local Docker daemon on the runner
|
||||
load: true
|
||||
target: rosenpass
|
||||
tags: rosenpass:test
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
- name: Integration Test - Standalone Key Exchange
|
||||
run: |
|
||||
# Create separate workdirs
|
||||
mkdir -p workdir-server workdir-client
|
||||
|
||||
# Create a Docker network
|
||||
docker network create -d bridge rp
|
||||
|
||||
echo "=== GENERATE SERVER KEYS ==="
|
||||
docker run --rm \
|
||||
-v $PWD/workdir-server:/workdir \
|
||||
rosenpass:test gen-keys \
|
||||
--public-key=workdir/server-public \
|
||||
--secret-key=workdir/server-secret
|
||||
|
||||
echo "=== GENERATE CLIENT KEYS ==="
|
||||
docker run --rm \
|
||||
-v $PWD/workdir-client:/workdir \
|
||||
rosenpass:test gen-keys \
|
||||
--public-key=workdir/client-public \
|
||||
--secret-key=workdir/client-secret
|
||||
|
||||
echo "=== SHARE PUBLIC KEYS ==="
|
||||
cp workdir-client/client-public workdir-server/client-public
|
||||
cp workdir-server/server-public workdir-client/server-public
|
||||
|
||||
echo "=== START SERVER CONTAINER ==="
|
||||
docker run -d --rm \
|
||||
--name rpserver \
|
||||
--network rp \
|
||||
-v $PWD/workdir-server:/workdir \
|
||||
rosenpass:test exchange \
|
||||
private-key workdir/server-secret \
|
||||
public-key workdir/server-public \
|
||||
listen 0.0.0.0:9999 \
|
||||
peer public-key workdir/client-public \
|
||||
outfile workdir/server-sharedkey
|
||||
|
||||
# Get the container IP of the server
|
||||
SERVER_IP=$(docker inspect --format='{{.NetworkSettings.Networks.rp.IPAddress}}' rpserver)
|
||||
echo "SERVER_IP=$SERVER_IP"
|
||||
|
||||
echo "=== START CLIENT CONTAINER ==="
|
||||
docker run -d --rm \
|
||||
--name rpclient \
|
||||
--network rp \
|
||||
-v $PWD/workdir-client:/workdir \
|
||||
rosenpass:test exchange \
|
||||
private-key workdir/client-secret \
|
||||
public-key workdir/client-public \
|
||||
peer public-key workdir/server-public \
|
||||
endpoint ${SERVER_IP}:9999 \
|
||||
outfile workdir/client-sharedkey
|
||||
|
||||
echo "=== COMPARE SHARED KEYS ==="
|
||||
echo "Waiting up to 30 seconds for the server to generate 'server-sharedkey'..."
|
||||
for i in $(seq 1 30); do
|
||||
if [ -f "workdir-server/server-sharedkey" ]; then
|
||||
echo "server-sharedkey found!"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
sudo cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
|
||||
|
||||
echo "Standalone Key Exchange test OK."
|
||||
# --------------------------------
|
||||
# 2. PUSH (only if tests pass)
|
||||
# --------------------------------
|
||||
docker-image-rp:
|
||||
needs:
|
||||
- build-and-test-rp
|
||||
# Skip if this is not a PR. Then we want to push this image.
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
# Use a matrix to build for both AMD64 and ARM64
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# Switch the runner based on the architecture
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/rp
|
||||
labels: |
|
||||
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.title=Rosenpass
|
||||
org.opencontainers.image.description=The rp command-line integrates Rosenpass and WireGuard to help you create a VPN
|
||||
org.opencontainers.image.vendor=Rosenpass e.V.
|
||||
org.opencontainers.image.licenses=MIT OR Apache-2.0
|
||||
org.opencontainers.image.url=https://rosenpass.eu
|
||||
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
|
||||
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ghcr.io/${{ github.repository_owner }}/rp
|
||||
target: rp
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-rp-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
docker-image-rosenpass:
|
||||
needs:
|
||||
- build-and-test-rp
|
||||
# Skip if this is not a PR. Then we want to push this image.
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
# Use a matrix to build for both AMD64 and ARM64
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# Switch the runner based on the architecture
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/rosenpass
|
||||
labels: |
|
||||
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.title=Rosenpass
|
||||
org.opencontainers.image.description=Reference implementation of the protocol rosenpass protocol
|
||||
org.opencontainers.image.vendor=Rosenpass e.V.
|
||||
org.opencontainers.image.licenses=MIT OR Apache-2.0
|
||||
org.opencontainers.image.url=https://rosenpass.eu
|
||||
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
|
||||
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ghcr.io/${{ github.repository_owner }}/rosenpass
|
||||
target: rosenpass
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-rosenpass-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge-digests:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- docker-image-rosenpass
|
||||
- docker-image-rp
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
strategy:
|
||||
matrix:
|
||||
target: [rp, rosenpass]
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-${{ matrix.target }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}
|
||||
tags: |
|
||||
type=edge,branch=main
|
||||
type=sha,branch=main
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}:${{ steps.meta.outputs.version }}
|
||||
166
.github/workflows/integration.yml
vendored
Normal file
166
.github/workflows/integration.yml
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
name: Integration Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
integration-tests-x86_64-linux:
|
||||
name: Integration tests x86_64-linux
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Extract the reference of before and after for the integration tests.
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
REF_BEFORE=""
|
||||
REF_AFTER="path:../../"
|
||||
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
echo "This CI run was triggered in the context of a pull request."
|
||||
REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "This CI run was triggered in the context of a push."
|
||||
REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
else
|
||||
echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
exit 1
|
||||
fi
|
||||
echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
- name: Check
|
||||
run: |
|
||||
cd ./tests/integration
|
||||
nix flake check --print-build-logs --system x86_64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL WE GET AN ARM64 RUNNER THAT SUPPORTS KVM
|
||||
#integration-tests-aarch64-linux:
|
||||
# name: Integration tests aarch64-linux
|
||||
# runs-on:
|
||||
# - ubicloud-standard-2-arm-ubuntu-2204
|
||||
# steps:
|
||||
# - uses: actions/checkout@v5
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# #git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# #git checkout -B ${{ github.ref_name }}
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# # export QEMU_OPTS="-machine virt -cpu cortex-a57"
|
||||
# nix flake check --print-build-logs --system aarch64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
#integration-tests-i686-linux:
|
||||
# name: Integration tests i686-linux
|
||||
# timeout-minutes: 144000
|
||||
# runs-on:
|
||||
# - ubicloud-standard-8-ubuntu-2204
|
||||
# steps:
|
||||
# - uses: actions/checkout@v5
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# nix flake check --print-build-logs --system i686-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL THIS ISSUE WITH NIXOS TESTS ON DARWIN GETS RESOLVED: https://github.com/NixOS/nixpkgs/issues/294725
|
||||
#integration-tests-aarch64-darwin:
|
||||
# name: Integration tests aarch64-darwin
|
||||
# runs-on:
|
||||
# - warp-macos-13-arm64-6x
|
||||
# steps:
|
||||
# - uses: actions/checkout@v5
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Extract the reference of before and after for the integration tests.
|
||||
# run: |
|
||||
# EVENT_NAME="${{ github.event_name }}"
|
||||
# REF_BEFORE=""
|
||||
# REF_AFTER="path:../../"
|
||||
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
# echo "This CI run was triggered in the context of a pull request."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/main"
|
||||
# git checkout -B pr-${{ github.event.pull_request.number }}
|
||||
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
|
||||
# elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
# echo "This CI run was triggered in the context of a push."
|
||||
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
|
||||
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
|
||||
# else
|
||||
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
# exit 1
|
||||
# fi
|
||||
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
|
||||
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
|
||||
# - name: Check
|
||||
# run: |
|
||||
# cd ./tests/integration
|
||||
# nix flake check --print-build-logs --system aarch64-darwin --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
|
||||
19
.github/workflows/manual-mac-pr.yaml
vendored
Normal file
19
.github/workflows/manual-mac-pr.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: PR Validation on Mac
|
||||
on:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
checks: write
|
||||
contents: write
|
||||
concurrency:
|
||||
group: manual-mac-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
qc:
|
||||
uses: ./.github/workflows/qc-mac.yaml
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
nix:
|
||||
uses: ./.github/workflows/nix-mac.yaml
|
||||
permissions:
|
||||
contents: write
|
||||
114
.github/workflows/nix-mac.yaml
vendored
Normal file
114
.github/workflows/nix-mac.yaml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
name: Nix on Mac
|
||||
permissions:
|
||||
contents: write
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
aarch64-darwin---default:
|
||||
name: Build aarch64-darwin.default
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.default --print-build-logs
|
||||
aarch64-darwin---release-package:
|
||||
name: Build aarch64-darwin.release-package
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
- aarch64-darwin---rp
|
||||
- aarch64-darwin---rosenpass-oci-image
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.release-package --print-build-logs
|
||||
aarch64-darwin---rosenpass:
|
||||
name: Build aarch64-darwin.rosenpass
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rosenpass --print-build-logs
|
||||
aarch64-darwin---rp:
|
||||
name: Build aarch64-darwin.rp
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rp --print-build-logs
|
||||
aarch64-darwin---rosenpass-oci-image:
|
||||
name: Build aarch64-darwin.rosenpass-oci-image
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rosenpass-oci-image --print-build-logs
|
||||
aarch64-darwin---check:
|
||||
name: Run Nix checks on aarch64-darwin
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
320
.github/workflows/nix.yaml
vendored
320
.github/workflows/nix.yaml
vendored
@@ -6,19 +6,24 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
i686-linux---default:
|
||||
name: Build i686-linux.default
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- i686-linux---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -27,14 +32,14 @@ jobs:
|
||||
i686-linux---rosenpass:
|
||||
name: Build i686-linux.rosenpass
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -43,15 +48,15 @@ jobs:
|
||||
i686-linux---rosenpass-oci-image:
|
||||
name: Build i686-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- i686-linux---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -60,113 +65,31 @@ jobs:
|
||||
i686-linux---check:
|
||||
name: Run Nix checks on i686-linux
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
x86_64-darwin---default:
|
||||
name: Build x86_64-darwin.default
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.default --print-build-logs
|
||||
x86_64-darwin---release-package:
|
||||
name: Build x86_64-darwin.release-package
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
- x86_64-darwin---rosenpass-oci-image
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.release-package --print-build-logs
|
||||
x86_64-darwin---rosenpass:
|
||||
name: Build x86_64-darwin.rosenpass
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.rosenpass --print-build-logs
|
||||
x86_64-darwin---rosenpass-oci-image:
|
||||
name: Build x86_64-darwin.rosenpass-oci-image
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.rosenpass-oci-image --print-build-logs
|
||||
x86_64-darwin---check:
|
||||
name: Run Nix checks on x86_64-darwin
|
||||
runs-on:
|
||||
- macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
run: |
|
||||
nix flake check . --print-build-logs
|
||||
x86_64-linux---default:
|
||||
name: Build x86_64-linux.default
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- x86_64-linux---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -175,15 +98,15 @@ jobs:
|
||||
x86_64-linux---proof-proverif:
|
||||
name: Build x86_64-linux.proof-proverif
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- x86_64-linux---proverif-patched
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -192,14 +115,14 @@ jobs:
|
||||
x86_64-linux---proverif-patched:
|
||||
name: Build x86_64-linux.proverif-patched
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -208,82 +131,187 @@ jobs:
|
||||
x86_64-linux---release-package:
|
||||
name: Build x86_64-linux.release-package
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- x86_64-linux---rosenpass-static-oci-image
|
||||
- x86_64-linux---rosenpass-static
|
||||
- x86_64-linux---rosenpass-static-oci-image
|
||||
- x86_64-linux---rp-static
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.release-package --print-build-logs
|
||||
# aarch64-linux---release-package:
|
||||
# name: Build aarch64-linux.release-package
|
||||
# runs-on:
|
||||
# - ubicloud-standard-2-arm-ubuntu-2204
|
||||
# needs:
|
||||
# - aarch64-linux---rosenpass-oci-image
|
||||
# - aarch64-linux---rosenpass
|
||||
# - aarch64-linux---rp
|
||||
# steps:
|
||||
# - run: |
|
||||
# DEBIAN_FRONTEND=noninteractive
|
||||
# sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
|
||||
# - uses: actions/checkout@v5
|
||||
# - uses: cachix/install-nix-action@v30
|
||||
# with:
|
||||
# nix_path: nixpkgs=channel:nixos-unstable
|
||||
# extra_nix_config: |
|
||||
# system = aarch64-linux
|
||||
# - uses: cachix/cachix-action@v15
|
||||
# with:
|
||||
# name: rosenpass
|
||||
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
# - name: Build
|
||||
# run: nix build .#packages.aarch64-linux.release-package --print-build-logs
|
||||
x86_64-linux---rosenpass:
|
||||
name: Build x86_64-linux.rosenpass
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.rosenpass --print-build-logs
|
||||
aarch64-linux---rosenpass:
|
||||
name: Build aarch64-linux.rosenpass
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
extra_nix_config: |
|
||||
system = aarch64-linux
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-linux.rosenpass --print-build-logs
|
||||
aarch64-linux---rp:
|
||||
name: Build aarch64-linux.rp
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
extra_nix_config: |
|
||||
system = aarch64-linux
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-linux.rp --print-build-logs
|
||||
x86_64-linux---rosenpass-oci-image:
|
||||
name: Build x86_64-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- x86_64-linux---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.rosenpass-oci-image --print-build-logs
|
||||
aarch64-linux---rosenpass-oci-image:
|
||||
name: Build aarch64-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
needs:
|
||||
- aarch64-linux---rosenpass
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
extra_nix_config: |
|
||||
system = aarch64-linux
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-linux.rosenpass-oci-image --print-build-logs
|
||||
x86_64-linux---rosenpass-static:
|
||||
name: Build x86_64-linux.rosenpass-static
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.rosenpass-static --print-build-logs
|
||||
x86_64-linux---rp-static:
|
||||
name: Build x86_64-linux.rp-static
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.rp-static --print-build-logs
|
||||
x86_64-linux---rosenpass-static-oci-image:
|
||||
name: Build x86_64-linux.rosenpass-static-oci-image
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs:
|
||||
- x86_64-linux---rosenpass-static
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -292,14 +320,14 @@ jobs:
|
||||
x86_64-linux---whitepaper:
|
||||
name: Build x86_64-linux.whitepaper
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -308,13 +336,13 @@ jobs:
|
||||
x86_64-linux---check:
|
||||
name: Run Nix checks on x86_64-linux
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -322,14 +350,14 @@ jobs:
|
||||
run: nix flake check . --print-build-logs
|
||||
x86_64-linux---whitepaper-upload:
|
||||
name: Upload whitepaper x86_64-linux
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
@@ -338,7 +366,7 @@ jobs:
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-linux.whitepaper --print-build-logs
|
||||
- name: Deploy PDF artifacts
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: result/
|
||||
|
||||
32
.github/workflows/qc-mac.yaml
vendored
Normal file
32
.github/workflows/qc-mac.yaml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: QC Mac
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cargo-test-mac:
|
||||
runs-on: warp-macos-13-arm64-6x
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
# liboqs requires quite a lot of stack memory, thus we adjust
|
||||
# the default stack size picked for new threads (which is used
|
||||
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
|
||||
- run: RUST_MIN_STACK=8388608 cargo test --workspace --all-features
|
||||
160
.github/workflows/qc.yaml
vendored
160
.github/workflows/qc.yaml
vendored
@@ -4,40 +4,60 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actionsx/prettier@v2
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actionsx/prettier@v3
|
||||
with:
|
||||
args: --check .
|
||||
|
||||
shellcheck:
|
||||
name: Shellcheck
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
|
||||
rustfmt:
|
||||
name: Rust Format
|
||||
runs-on: ubuntu-latest
|
||||
name: Rust code formatting
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run Rust Formatting Script
|
||||
run: bash format_rust_code.sh --mode check
|
||||
|
||||
cargo-bench:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup component add rustfmt
|
||||
- name: Run Cargo Fmt
|
||||
run: cargo fmt --all --check
|
||||
- name: Run Rust Markdown code block Formatting Script
|
||||
run: bash format_rust_code.sh --mode check
|
||||
|
||||
cargo-bench:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -46,26 +66,34 @@ jobs:
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install libsodium
|
||||
run: sudo apt-get install -y libsodium-dev
|
||||
# liboqs requires quite a lot of stack memory, thus we adjust
|
||||
# the default stack size picked for new threads (which is used
|
||||
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
|
||||
- run: RUST_MIN_STACK=8388608 cargo bench --no-run --workspace
|
||||
- run: RUST_MIN_STACK=8388608 cargo bench --workspace --exclude rosenpass-fuzzing
|
||||
|
||||
mandoc:
|
||||
name: mandoc
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- name: Install mandoc
|
||||
run: sudo apt-get install -y mandoc
|
||||
- uses: actions/checkout@v5
|
||||
- name: Check rp.1
|
||||
run: doc/check.sh doc/rp.1
|
||||
|
||||
cargo-audit:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions-rs/audit-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
cargo-clippy:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -75,18 +103,16 @@ jobs:
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- run: rustup component add clippy
|
||||
- name: Install libsodium
|
||||
run: sudo apt-get install -y libsodium-dev
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
cargo-doc:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -96,18 +122,16 @@ jobs:
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- run: rustup component add clippy
|
||||
- name: Install libsodium
|
||||
run: sudo apt-get install -y libsodium-dev
|
||||
# `--no-deps` used as a workaround for a rust compiler bug. See:
|
||||
# - https://github.com/rosenpass/rosenpass/issues/62
|
||||
# - https://github.com/rust-lang/rust/issues/108378
|
||||
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
|
||||
|
||||
cargo-test:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -116,19 +140,17 @@ jobs:
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install libsodium
|
||||
run: sudo apt-get install -y libsodium-dev
|
||||
# liboqs requires quite a lot of stack memory, thus we adjust
|
||||
# the default stack size picked for new threads (which is used
|
||||
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
|
||||
- run: RUST_MIN_STACK=8388608 cargo test --workspace
|
||||
- run: RUST_MIN_STACK=8388608 cargo test --workspace --all-features
|
||||
|
||||
cargo-test-nix-devshell-x86_64-linux:
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -137,20 +159,20 @@ jobs:
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- uses: cachix/install-nix-action@v21
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- run: nix develop --command cargo test --workspace
|
||||
- run: nix develop --command cargo test --workspace --all-features
|
||||
|
||||
cargo-fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
@@ -159,12 +181,10 @@ jobs:
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install libsodium
|
||||
run: sudo apt-get install -y libsodium-dev
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup override set nightly
|
||||
- name: Install cargo-fuzz
|
||||
run: cargo install cargo-fuzz
|
||||
- name: Run fuzzing
|
||||
@@ -174,5 +194,43 @@ jobs:
|
||||
cargo fuzz run fuzz_handle_msg -- -max_total_time=5
|
||||
ulimit -s 8192000 && RUST_MIN_STACK=33554432000 && cargo fuzz run fuzz_kyber_encaps -- -max_total_time=5
|
||||
cargo fuzz run fuzz_mceliece_encaps -- -max_total_time=5
|
||||
cargo fuzz run fuzz_box_secret_alloc -- -max_total_time=5
|
||||
cargo fuzz run fuzz_vec_secret_alloc -- -max_total_time=5
|
||||
cargo fuzz run fuzz_box_secret_alloc_malloc -- -max_total_time=5
|
||||
cargo fuzz run fuzz_box_secret_alloc_memfdsec -- -max_total_time=5
|
||||
cargo fuzz run fuzz_box_secret_alloc_memfdsec_mallocfb -- -max_total_time=5
|
||||
cargo fuzz run fuzz_vec_secret_alloc_malloc -- -max_total_time=5
|
||||
cargo fuzz run fuzz_vec_secret_alloc_memfdsec -- -max_total_time=5
|
||||
cargo fuzz run fuzz_vec_secret_alloc_memfdsec_mallocfb -- -max_total_time=5
|
||||
|
||||
codecov:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: nightly
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup component add llvm-tools-preview
|
||||
- run: |
|
||||
cargo install cargo-llvm-cov || true
|
||||
cargo install grcov || true
|
||||
./coverage_report.sh
|
||||
# If using tarapulin
|
||||
#- run: cargo install cargo-tarpaulin
|
||||
#- run: cargo tarpaulin --out Xml
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./target/grcov/lcov
|
||||
verbose: true
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
37
.github/workflows/regressions.yml
vendored
Normal file
37
.github/workflows/regressions.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Regressions
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
multi-peer:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- run: cargo build --bin rosenpass --release
|
||||
- run: python misc/generate_configs.py
|
||||
- run: chmod +x .ci/run-regression.sh
|
||||
- run: .ci/run-regression.sh 100 20
|
||||
- run: |
|
||||
[ $(ls -1 output/ate/out | wc -l) -eq 100 ]
|
||||
|
||||
boot-race:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- run: cargo build --bin rosenpass --release
|
||||
- run: chmod +x .ci/boot_race/run.sh
|
||||
- run: cargo run --release --bin rosenpass gen-keys .ci/boot_race/a.toml
|
||||
- run: cargo run --release --bin rosenpass gen-keys .ci/boot_race/b.toml
|
||||
- run: .ci/boot_race/run.sh 5 2 .ci/boot_race/a.toml .ci/boot_race/b.toml
|
||||
- run: .ci/boot_race/run.sh 5 1 .ci/boot_race/a.toml .ci/boot_race/b.toml
|
||||
- run: .ci/boot_race/run.sh 5 0 .ci/boot_race/a.toml .ci/boot_race/b.toml
|
||||
49
.github/workflows/release.yaml
vendored
49
.github/workflows/release.yaml
vendored
@@ -11,18 +11,16 @@ jobs:
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build release
|
||||
run: nix build .#release-package --print-build-logs
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
@@ -32,18 +30,16 @@ jobs:
|
||||
runs-on:
|
||||
- macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build release
|
||||
run: nix build .#release-package --print-build-logs
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
@@ -53,19 +49,40 @@ jobs:
|
||||
runs-on:
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build release
|
||||
run: nix build .#release-package --print-build-logs
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
files: result/*
|
||||
linux-packages:
|
||||
name: Build and upload DEB and RPM packages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build DEB & RPM package
|
||||
run: |
|
||||
mkdir packages
|
||||
for f in $(nix build .#package-deb .#package-rpm --print-out-paths); do cp "$f" "packages/${f#*-}"; done
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
files: |
|
||||
packages/*
|
||||
|
||||
177
.github/workflows/supply-chain.yml
vendored
Normal file
177
.github/workflows/supply-chain.yml
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
name: Supply-Chain
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
name: Deny dependencies with vulnerabilities or incompatible licenses
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||
cargo-supply-chain:
|
||||
name: Supply Chain Report
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cache/cargo-supply-chain/
|
||||
key: cargo-supply-chain-cache
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-supply-chain
|
||||
key: cargo-supply-chain-bin
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-supply-chain/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-supply-chain binary
|
||||
run: cargo install --root ${{ runner.tool_cache }}/cargo-supply-chain cargo-supply-chain
|
||||
- name: Update data for cargo-supply-chain
|
||||
run: cargo supply-chain update
|
||||
- name: Generate cargo-supply-chain report about publishers
|
||||
run: cargo supply-chain publishers
|
||||
- name: Generate cargo-supply-chain report about crates
|
||||
run: cargo supply-chain crates
|
||||
# The setup for cargo-vet follows the recommendations in the cargo-vet documentation: https://mozilla.github.io/cargo-vet/configuring-ci.html
|
||||
cargo-vet:
|
||||
name: Vet Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
key: cargo-vet-cache
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-vet
|
||||
key: cargo-vet-bin
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-vet binary
|
||||
run: cargo install --root ${{ runner.tool_cache }}/cargo-vet cargo-vet
|
||||
- name: Check which event triggered this CI run, a push or a pull request.
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
IS_PR="false"
|
||||
IS_PUSH="false"
|
||||
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
echo "This CI run was triggered in the context of a pull request."
|
||||
IS_PR="true"
|
||||
elif [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "This CI run was triggered in the context of a push."
|
||||
IS_PUSH="true"
|
||||
else
|
||||
echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
|
||||
exit 1
|
||||
fi
|
||||
echo "IS_PR=$IS_PR" >> $GITHUB_ENV
|
||||
echo "IS_PUSH=$IS_PUSH" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Check if last commit was by Dependabot
|
||||
run: |
|
||||
# Depending on the trigger for, the relevant commit has to be deduced differently.
|
||||
if [[ "$IS_PR" == true ]]; then
|
||||
# This is the commit ID for the last commit to the head branch of the pull request.
|
||||
# If we used github.sha here instead, it would point to a merge commit between the PR and the main branch, which is only created for the CI run.
|
||||
SHA="${{ github.event.pull_request.head.sha }}"
|
||||
REF="${{ github.head_ref }}"
|
||||
elif [[ "$IS_PUSH" == "true" ]]; then
|
||||
SHA="${{ github.sha }}" # This is the last commit to the branch.
|
||||
REF=${GITHUB_REF#refs/heads/}
|
||||
else
|
||||
echo "ERROR: This action only supports pull requests and push events as triggers. Exiting with error."
|
||||
exit 1
|
||||
fi
|
||||
echo "Commit SHA is $SHA"
|
||||
echo "Branch is $REF"
|
||||
echo "REF=$REF" >> $GITHUB_ENV
|
||||
|
||||
COMMIT_AUTHOR=$(gh api repos/${{ github.repository }}/commits/$SHA --jq .author.login) # .author.login might be null, but for dependabot it will always be there and cannot be spoofed in contrast to .commit.author.name
|
||||
echo "The author of the last commit is $COMMIT_AUTHOR"
|
||||
if [[ "$COMMIT_AUTHOR" == "dependabot[bot]" ]]; then
|
||||
echo "The last commit was made by dependabot"
|
||||
LAST_COMMIT_IS_BY_DEPENDABOT=true
|
||||
else
|
||||
echo "The last commit was made by $COMMIT_AUTHOR not by dependabot"
|
||||
LAST_COMMIT_IS_BY_DEPENDABOT=false
|
||||
fi
|
||||
echo "LAST_COMMIT_IS_BY_DEPENDABOT=$LAST_COMMIT_IS_BY_DEPENDABOT" >> $GITHUB_ENV
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
- name: Check if the last commit's message ends in "--regenerate-exemptions"
|
||||
run: |
|
||||
# Get commit message
|
||||
COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
|
||||
if [[ "$COMMIT_MESSAGE" == *"--regenerate-exemptions" ]]; then
|
||||
echo "The last commit message ends in --regenerate-exemptions"
|
||||
REGEN_EXEMP=true
|
||||
else
|
||||
echo "The last commit message does not end in --regenerate-exemptions"
|
||||
REGEN_EXEMP=false
|
||||
fi
|
||||
echo "REGEN_EXEMP=$REGEN_EXEMP" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Check if the CI run happens in the context of a dependabot PR # Even if a PR is created by dependabot, the last commit can, and often should be, the regeneration of the cargo vet exemptions. It could also be from an individual making manual changes.
|
||||
run: |
|
||||
IN_DEPENDABOT_PR_CONTEXT="false"
|
||||
if [[ $IS_PR == "true" && "${{ github.event.pull_request.user.login }}" == "dependabot[bot]" ]]; then
|
||||
IN_DEPENDABOT_PR_CONTEXT="true"
|
||||
echo "This CI run is in the context of PR by dependabot."
|
||||
else
|
||||
echo "This CI run is NOT in the context of PR by dependabot."
|
||||
IN_DEPENDABOT_PR_CONTEXT="false"
|
||||
fi
|
||||
echo "IN_DEPENDABOT_PR_CONTEXT=$IN_DEPENDABOT_PR_CONTEXT" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- uses: actions/checkout@v5
|
||||
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true'
|
||||
with:
|
||||
token: ${{ secrets.CI_BOT_PAT }}
|
||||
- name: In case of a dependabot PR, ensure that we are not in a detached HEAD state
|
||||
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true'
|
||||
run: |
|
||||
git fetch origin $REF # ensure that we are up to date.
|
||||
git switch $REF # ensure that we are NOT in a detached HEAD state. This is important for the commit action in the end
|
||||
shell: bash
|
||||
- name: Regenerate cargo vet exemptions if we are in the context of a PR created by dependabot and the last commit is by dependabot or a regeneration of cargo vet exemptions was explicitly requested.
|
||||
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true' && (env.LAST_COMMIT_IS_BY_DEPENDABOT == 'true' || env.REGEN_EXEMP=='true') # Run only for Dependabot PRs or if specifically requested
|
||||
run: cargo vet regenerate exemptions
|
||||
- name: Commit and push changes if we are in the context of a PR created by dependabot and the last commit is by dependabot or a regeneration of cargo vet exemptions was explicitly requested.
|
||||
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true' && (env.LAST_COMMIT_IS_BY_DEPENDABOT == 'true' || env.REGEN_EXEMP=='true')
|
||||
uses: stefanzweifel/git-auto-commit-action@v6
|
||||
with:
|
||||
commit_message: Regenerate cargo vet exemptions
|
||||
commit_user_name: rosenpass-ci-bot[bot]
|
||||
commit_user_email: noreply@rosenpass.eu
|
||||
commit_author: Rosenpass CI Bot <noreply@rosenpass.eu>
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CI_BOT_PAT }}
|
||||
- name: Invoke cargo-vet
|
||||
run: cargo vet --locked
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -20,3 +20,9 @@ _markdown_*
|
||||
**/result
|
||||
**/result-*
|
||||
.direnv
|
||||
|
||||
# Visual studio code
|
||||
.vscode
|
||||
|
||||
/output
|
||||
.nixos-test-history
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
.direnv/
|
||||
flake.lock
|
||||
papers/whitepaper.md
|
||||
target/
|
||||
src/usage.md
|
||||
target/
|
||||
|
||||
41
CONTRIBUTING.md
Normal file
41
CONTRIBUTING.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Contributing to Rosenpass
|
||||
|
||||
## Common operations
|
||||
|
||||
### Apply code formatting
|
||||
|
||||
Format rust code:
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
Format rust code in markdown files:
|
||||
|
||||
```bash
|
||||
./format_rust_code.sh --mode fix
|
||||
```
|
||||
|
||||
### Spawn a development environment with nix
|
||||
|
||||
```bash
|
||||
nix develop .#fullEnv
|
||||
```
|
||||
|
||||
You need to [install this nix package manager](https://wiki.archlinux.org/title/Nix) first.
|
||||
|
||||
### Run our test
|
||||
|
||||
Make sure to increase the stack size available; some of our cryptography operations require a lot of stack memory.
|
||||
|
||||
```bash
|
||||
RUST_MIN_STACK=8388608 cargo test --workspace --all-features
|
||||
```
|
||||
|
||||
### Generate coverage reports
|
||||
|
||||
Keep in mind that many of Rosenpass' tests are doctests, so to get an accurate read on our code coverage, you have to include doctests:
|
||||
|
||||
```bash
|
||||
./coverage_report.sh
|
||||
```
|
||||
2178
Cargo.lock
generated
2178
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
119
Cargo.toml
119
Cargo.toml
@@ -2,23 +2,20 @@
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"lenses",
|
||||
"wireguard-broker",
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"rp",
|
||||
"wireguard-broker",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
"rosenpass",
|
||||
"wireguard-broker"
|
||||
]
|
||||
default-members = ["rosenpass", "rp", "wireguard-broker"]
|
||||
|
||||
[workspace.metadata.release]
|
||||
# ensure that adding `--package` as argument to `cargo release` still creates version tags in the form of `vx.y.z`
|
||||
@@ -33,36 +30,78 @@ rosenpass-ciphers = { path = "ciphers" }
|
||||
rosenpass-to = { path = "to" }
|
||||
rosenpass-secret-memory = { path = "secret-memory" }
|
||||
rosenpass-oqs = { path = "oqs" }
|
||||
rosenpass-lenses = { path = "lenses" }
|
||||
rosenpass-wireguard-broker = { path = "wireguard-broker" }
|
||||
criterion = "0.4.0"
|
||||
test_bin = "0.4.0"
|
||||
libfuzzer-sys = "0.4"
|
||||
stacker = "0.1.15"
|
||||
doc-comment = "0.3.3"
|
||||
base64 = "0.21.5"
|
||||
zeroize = "1.7.0"
|
||||
memoffset = "0.9.0"
|
||||
thiserror = "1.0.50"
|
||||
paste = "1.0.14"
|
||||
env_logger = "0.10.1"
|
||||
base64ct = { version = "1.6.0", default-features = false }
|
||||
zeroize = "1.8.1"
|
||||
memoffset = "0.9.1"
|
||||
thiserror = "1.0.69"
|
||||
paste = "1.0.15"
|
||||
env_logger = "0.10.2"
|
||||
toml = "0.7.8"
|
||||
static_assertions = "1.1.0"
|
||||
allocator-api2 = "0.2.14"
|
||||
allocator-api2-tests = "0.2.14"
|
||||
memsec = "0.6.3"
|
||||
memsec = { git = "https://github.com/rosenpass/memsec.git", rev = "aceb9baee8aec6844125bd6612f92e9a281373df", features = [
|
||||
"alloc_ext",
|
||||
] }
|
||||
rand = "0.8.5"
|
||||
wireguard-uapi = "3.0.0"
|
||||
command-fds = "0.2.3"
|
||||
rustix = { version = "0.38.27", features = ["net"] }
|
||||
tokio = { version = "1.34.0", features = ["sync", "full", "mio"] }
|
||||
typenum = "1.17.0"
|
||||
log = { version = "0.4.20" }
|
||||
clap = { version = "4.4.10", features = ["derive"] }
|
||||
serde = { version = "1.0.193", features = ["derive"] }
|
||||
arbitrary = { version = "1.3.2", features = ["derive"] }
|
||||
anyhow = { version = "1.0.75", features = ["backtrace", "std"] }
|
||||
mio = { version = "0.8.9", features = ["net", "os-poll"] }
|
||||
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
|
||||
log = { version = "0.4.27" }
|
||||
clap = { version = "4.5.23", features = ["derive"] }
|
||||
clap_mangen = "0.2.29"
|
||||
clap_complete = "4.5.40"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
arbitrary = { version = "1.4.1", features = ["derive"] }
|
||||
anyhow = { version = "1.0.98", features = ["backtrace", "std"] }
|
||||
mio = { version = "1.0.3", features = ["net", "os-poll"] }
|
||||
signal-hook-mio = { version = "0.2.4", features = ["support-v1_0"] }
|
||||
signal-hook = "0.3.17"
|
||||
oqs-sys = { version = "0.9.1", default-features = false, features = [
|
||||
'classic_mceliece',
|
||||
'kyber',
|
||||
] }
|
||||
blake2 = "0.10.6"
|
||||
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [ "std", "heapless" ] }
|
||||
sha3 = "0.10.8"
|
||||
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [
|
||||
"std",
|
||||
"heapless",
|
||||
] }
|
||||
zerocopy = { version = "0.8.27", features = ["derive"] }
|
||||
home = "=0.5.9" # 5.11 requires rustc 1.81
|
||||
derive_builder = "0.20.1"
|
||||
tokio = { version = "1.46", features = ["macros", "rt-multi-thread"] }
|
||||
postcard = { version = "1.1.1", features = ["alloc"] }
|
||||
libcrux = { version = "0.0.2-pre.2" }
|
||||
libcrux-chacha20poly1305 = { version = "0.0.2-beta.3" }
|
||||
libcrux-ml-kem = { version = "0.0.2-beta.3" }
|
||||
libcrux-blake2 = { git = "https://github.com/cryspen/libcrux.git", rev = "10ce653e9476" }
|
||||
libcrux-test-utils = { git = "https://github.com/cryspen/libcrux.git", rev = "0ab6d2dd9c1f" }
|
||||
hex-literal = { version = "0.4.1" }
|
||||
hex = { version = "0.4.3" }
|
||||
heck = { version = "0.5.0" }
|
||||
libc = { version = "0.2" }
|
||||
errno = { version = "0.3.13" }
|
||||
uds = { git = "https://github.com/rosenpass/uds" }
|
||||
lazy_static = "1.5"
|
||||
|
||||
#Dev dependencies
|
||||
assert_tv = { version = "0.6.4" }
|
||||
base64 = { version = "0.22.1" }
|
||||
serial_test = "3.2.0"
|
||||
tempfile = "3"
|
||||
stacker = "0.1.21"
|
||||
libfuzzer-sys = "0.4"
|
||||
test_bin = "0.4.0"
|
||||
criterion = "0.5.1"
|
||||
allocator-api2-tests = "0.2.15"
|
||||
procspawn = { version = "1.0.1", features = ["test-support"] }
|
||||
serde_json = { version = "1.0.140" }
|
||||
bitflags = "2.9.3"
|
||||
|
||||
#Broker dependencies (might need cleanup or changes)
|
||||
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }
|
||||
command-fds = "0.2.3"
|
||||
rustix = { version = "0.38.42", features = ["net", "fs", "process"] }
|
||||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
x25519-dalek = "2"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
In this case the test uses secure rng and a fresh secure biscuit key.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.mpv"
|
||||
|
||||
#define CHAINING_KEY_EVENTS 1
|
||||
@@ -44,7 +43,6 @@
|
||||
#include "rosenpass/oracles.mpv"
|
||||
#include "crypto/kem.mpv"
|
||||
|
||||
#define INITIATOR_TEST
|
||||
#define NEW_TRUSTED_SEED(name) \
|
||||
new MCAT(name, _secret_seed):seed_prec; \
|
||||
name <- make_trusted_seed(MCAT(name, _secret_seed)); \
|
||||
@@ -57,52 +55,86 @@ free initiator1, initiator2:kem_sk_prec.
|
||||
free responder1, responder2:kem_sk_prec.
|
||||
|
||||
let secure_init_hello(initiator: kem_sk_tmpl, sidi : SessionId, psk: key_tmpl, responder: kem_sk_tmpl) =
|
||||
|
||||
new epkit:kem_pk; // epki
|
||||
new sctrt:bits; // sctr
|
||||
new pidi_ct:bits; // pidi_ct
|
||||
new autht:bits; // auth
|
||||
|
||||
NEW_TRUSTED_SEED(seski_trusted_seed)
|
||||
NEW_TRUSTED_SEED(ssptr_trusted_seed)
|
||||
Oinitiator_inner(sidi, initiator, psk, responder, seski_trusted_seed, ssptr_trusted_seed, D).
|
||||
new last_cookie:key;
|
||||
new call:Atom;
|
||||
|
||||
let secure_resp_hello(initiator: kem_sk_tmpl, responder: kem_sk_tmpl, sidr:SessionId, sidi:SessionId, biscuit_no:Atom, psk:key_tmpl) =
|
||||
in(D, Envelope(k, IH2b(InitHello(=sidi, epki, sctr, pidiC, auth))));
|
||||
ih <- InitHello(sidi, epki, sctr, pidiC, auth);
|
||||
Oinitiator_inner(sidi, initiator, psk, responder, seski_trusted_seed, ssptr_trusted_seed, last_cookie, D, call).
|
||||
|
||||
let secure_resp_hello(initiator: kem_sk_tmpl, responder: kem_sk_tmpl, sidi:SessionId, sidr:SessionId, biscuit_no:Atom, psk:key_tmpl) =
|
||||
|
||||
in(D, InitHello(=secure_sidi, epki, sctr, pidi_ct, auth));
|
||||
|
||||
ih <- InitHello(sidi, epki, sctr, pidi_ct, auth);
|
||||
NEW_TRUSTED_SEED(septi_trusted_seed)
|
||||
NEW_TRUSTED_SEED(sspti_trusted_seed)
|
||||
Oinit_hello_inner(sidr, biscuit_no, responder, psk, initiator, septi_trusted_seed, sspti_trusted_seed, ih, D).
|
||||
new last_cookie:key;
|
||||
new call:Atom;
|
||||
|
||||
Oinit_hello_inner(sidr, biscuit_no, responder, psk, initiator, septi_trusted_seed, sspti_trusted_seed, ih, last_cookie, D, call).
|
||||
|
||||
let secure_init_conf(initiator: kem_sk_tmpl, responder: kem_sk_tmpl, psk:key_tmpl, sidi:SessionId, sidr:SessionId) =
|
||||
in(D, Envelope(k3, IC2b(InitConf(=sidi, =sidr, biscuit, auth3))));
|
||||
in(D, InitConf(=sidi, =sidr, biscuit, auth3));
|
||||
ic <- InitConf(sidi,sidr,biscuit, auth3);
|
||||
NEW_TRUSTED_SEED(seski_trusted_seed)
|
||||
NEW_TRUSTED_SEED(ssptr_trusted_seed)
|
||||
Oinit_conf_inner(initiator, psk, responder, ic).
|
||||
new last_cookie:key;
|
||||
call <- Cinit_conf(initiator, psk, responder, ic);
|
||||
|
||||
let secure_communication(initiator: kem_sk_tmpl, responder:kem_sk_tmpl) =
|
||||
secure_key <- prepare_key(secure_psk);
|
||||
(!secure_init_hello(initiator, secure_sidi, secure_key, responder))
|
||||
| !secure_resp_hello(initiator, responder, secure_sidr, secure_sidi, secure_biscuit_no, secure_key)
|
||||
| !(secure_init_conf(initiator, responder, secure_key, secure_sidi, secure_sidr)).
|
||||
Oinit_conf_inner(initiator, psk, responder, ic, call).
|
||||
|
||||
let secure_communication(initiator: kem_sk_tmpl, responder:kem_sk_tmpl, key:key) =
|
||||
key_tmpl <- prepare_key(key);
|
||||
(!secure_init_hello(initiator, secure_sidi, key_tmpl, responder))
|
||||
| !secure_resp_hello(initiator, responder, secure_sidi, secure_sidr, secure_biscuit_no, key_tmpl)
|
||||
| !(secure_init_conf(initiator, responder, key_tmpl, secure_sidi, secure_sidr)).
|
||||
|
||||
let participant_communication_initiator(participant:kem_sk_tmpl) =
|
||||
in(C, responder:kem_sk_tmpl);
|
||||
in(C, k:key);
|
||||
secure_communication(participant, responder, k).
|
||||
|
||||
let participant_communication_responder(participant:kem_sk_tmpl) =
|
||||
in(C, initiator:kem_sk_tmpl);
|
||||
in(C, k:key);
|
||||
secure_communication(initiator, participant, k).
|
||||
|
||||
let participants_communication() =
|
||||
initiator1_tmpl <- make_trusted_kem_sk(initiator1);
|
||||
initiator2_tmpl <- make_trusted_kem_sk(initiator2);
|
||||
responder1_tmpl <- make_trusted_kem_sk(responder1);
|
||||
responder2_tmpl <- make_trusted_kem_sk(responder2);
|
||||
|
||||
!participant_communication_initiator(initiator1_tmpl) | !participant_communication_responder(initiator1_tmpl)
|
||||
| !participant_communication_initiator(initiator2_tmpl) | !participant_communication_responder(initiator2_tmpl)
|
||||
| !participant_communication_initiator(responder1_tmpl) | !participant_communication_responder(responder1_tmpl)
|
||||
| !participant_communication_initiator(responder2_tmpl) | !participant_communication_responder(responder2_tmpl).
|
||||
|
||||
let pipeChannel(D:channel, C:channel) =
|
||||
in(D, b:bits);
|
||||
out(C, b).
|
||||
|
||||
fun kem_private(kem_pk): kem_sk
|
||||
reduc forall sk_tmpl:kem_sk;
|
||||
kem_private(kem_pub(sk_tmpl)) = sk_tmpl[private].
|
||||
|
||||
let secretCommunication() =
|
||||
|
||||
#ifdef INITIATOR_TEST
|
||||
initiator_pk <- choice[setup_kem_pk(make_trusted_kem_sk(initiator1)), setup_kem_pk(make_trusted_kem_sk(initiator2))];
|
||||
initiator_seed <- prepare_kem_sk(kem_private(initiator_pk));
|
||||
initiator_seed <- choice[make_trusted_kem_sk(initiator1), make_trusted_kem_sk(initiator2)];
|
||||
#else
|
||||
initiator_seed <- prepare_kem_sk(trusted_kem_sk(initiator1));
|
||||
initiator_seed <- make_trusted_kem_sk(initiator1);
|
||||
#endif
|
||||
#ifdef RESPONDER_TEST
|
||||
responder_pk <- choice[setup_kem_pk(make_trusted_kem_sk(responder1)), setup_kem_pk(make_trusted_kem_sk(responder2))];
|
||||
responder_seed <- prepare_kem_sk(kem_private(responder_pk));
|
||||
responder_seed <- choice[make_trusted_kem_sk(responder1), make_trusted_kem_sk(responder2)];
|
||||
#else
|
||||
responder_seed <- prepare_kem_sk(trusted_kem_sk(responder1));
|
||||
responder_seed <- make_trusted_kem_sk(responder1);
|
||||
#endif
|
||||
secure_communication(initiator_seed, responder_seed) | !pipeChannel(D, C).
|
||||
|
||||
secure_communication(initiator_seed, responder_seed, secure_psk) | !pipeChannel(D, C).
|
||||
|
||||
let reveal_pks() =
|
||||
out(C, setup_kem_pk(make_trusted_kem_sk(responder1)));
|
||||
@@ -116,6 +148,8 @@ let rosenpass_main2() =
|
||||
| REP(RESPONDER_BOUND, Oinit_conf).
|
||||
|
||||
let identity_hiding_main() =
|
||||
0 | reveal_pks() | rosenpass_main2() | phase 1; secretCommunication().
|
||||
0 | reveal_pks() | rosenpass_main2() | participants_communication() | phase 1; secretCommunication().
|
||||
|
||||
#ifndef CUSTOM_MAIN
|
||||
let main = identity_hiding_main.
|
||||
#endif
|
||||
36
analysis/rosenpass/cookie.mpv
Normal file
36
analysis/rosenpass/cookie.mpv
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
fun cookie_key(kem_sk) : key [private].
|
||||
fun ip_and_port(kem_pk):bits.
|
||||
letfun create_mac2_key(sskm:kem_sk, spkt:kem_pk) = prf(cookie_key(sskm), ip_and_port(spkt)).
|
||||
|
||||
letfun create_cookie(sskm:kem_sk, spkm:kem_pk, spkt:kem_pk, nonce:bits, msg:bits) = xaead_enc(lprf2(COOKIE, kem_pk2b(spkm), nonce),
|
||||
k2b(create_mac2_key(sskm, spkm)), msg).
|
||||
|
||||
type CookieMsg_t.
|
||||
fun CookieMsg(
|
||||
SessionId, // sender
|
||||
bits, // nonce
|
||||
bits // cookie
|
||||
) : CookieMsg_t [data].
|
||||
|
||||
|
||||
#define COOKIE_PROCESS(eventLbl, innerFunc) \
|
||||
in(C, Ccookie(mac1, mac2)); \
|
||||
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (spkm, spkt, last_cookie);) \
|
||||
msgB <- Envelope(mac1, RH2b(rh)); \
|
||||
mac2_key <- create_mac2_key(sskm, spkt) \
|
||||
let RespHello(sidi, sidr, ecti, scti, biscuit_ct, auth) = rh in \
|
||||
if Envelope(mac2_key, msgB) = mac2 then \
|
||||
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (spkm, last_cookie);) \
|
||||
innerFunc \
|
||||
else \
|
||||
new nonce:bits; \
|
||||
cookie <- create_cookie(sskm, spkm, spkt, nonce, msg) \
|
||||
cookie_msg <- CookieMsg(sidi, nonce, cookie); \
|
||||
COOKIE_EV(event MCAT(eventLbl, _CookieSent) (spkm, cookie, cookie_k, cookie_msg);) \
|
||||
out(C, cookie_msg).
|
||||
|
||||
#define COOKIE_EVENTS(eventLbl) \
|
||||
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (kem_pk, kem_pk, bits).) \
|
||||
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (kem_pk, bits, key, CookieMsg_t).) \
|
||||
COOKIE_EV(event MCAT(eventLbl, _CookieSent) (kem_pk, bits).)
|
||||
@@ -143,10 +143,10 @@ letfun ENCRYPT_AND_MIX(ct, pt) \
|
||||
// TODO: Migrate kems to use binary ciphertexts directly
|
||||
#define ENCAPS_AND_MIX(ct, pk, shk) \
|
||||
ct <- kem_enc(pk, shk); \
|
||||
MIX3(kem_pk2b(pk), ct, k2b(shk))
|
||||
MIX3(kem_pk2b(pk), k2b(shk), ct)
|
||||
#define DECAPS_AND_MIX(sk, pk, ct) \
|
||||
DUMMY(shk) <- kem_dec(sk, ct); \
|
||||
MIX3(kem_pk2b(pk), ct, k2b(DUMMY(shk)))
|
||||
MIX3(kem_pk2b(pk), k2b(DUMMY(shk)), ct)
|
||||
|
||||
|
||||
// biscuits
|
||||
|
||||
@@ -47,16 +47,14 @@ CK_EV( event OskOinit_conf(key, key). )
|
||||
MTX_EV( event ICRjct(InitConf_t, key, kem_sk, kem_pk). )
|
||||
SES_EV( event ResponderSession(InitConf_t, key). )
|
||||
event ConsumeBiscuit(Atom, kem_sk, kem_pk, Atom).
|
||||
|
||||
let Oinit_conf_inner(Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:InitConf_t) =
|
||||
let Oinit_conf() =
|
||||
in(C, Cinit_conf(Ssskm, Spsk, Sspkt, ic));
|
||||
#if RANDOMIZED_CALL_IDS
|
||||
new call:Atom;
|
||||
#else
|
||||
call <- Cinit_conf(Ssskm, Spsk, Sspkt, ic);
|
||||
#endif
|
||||
|
||||
SETUP_HANDSHAKE_STATE()
|
||||
|
||||
eski <- kem_sk0;
|
||||
epki <- kem_pk0;
|
||||
let try_ = (
|
||||
@@ -74,10 +72,6 @@ let Oinit_conf_inner(Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:Ini
|
||||
0
|
||||
#endif
|
||||
).
|
||||
|
||||
let Oinit_conf() =
|
||||
in(C, Cinit_conf(Ssskm, Spsk, Sspkt, ic));
|
||||
Oinit_conf_inner(Ssskm, Spsk, Sspkt, ic).
|
||||
|
||||
restriction biscuit_no:Atom, sskm:kem_sk, spkr:kem_pk, ad1:Atom, ad2:Atom;
|
||||
event(ConsumeBiscuit(biscuit_no, sskm, spkr, ad1)) && event(ConsumeBiscuit(biscuit_no, sskm, spkr, ad2))
|
||||
@@ -91,9 +85,9 @@ CK_EV( event OskOresp_hello(key, key, key). )
|
||||
MTX_EV( event RHRjct(RespHello_t, key, kem_sk, kem_pk). )
|
||||
MTX_EV( event ICSent(RespHello_t, InitConf_t, key, kem_sk, kem_pk). )
|
||||
SES_EV( event InitiatorSession(RespHello_t, key). )
|
||||
let Oresp_hello(HS_DECL_ARGS, C_in:channel) =
|
||||
in(C_in, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit, auth)));
|
||||
rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth);
|
||||
let Oresp_hello(HS_DECL_ARGS) =
|
||||
in(C, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit_ct, auth)));
|
||||
rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth);
|
||||
/* try */ let ic = (
|
||||
ck_ini <- ck;
|
||||
RESPHELLO_CONSUME()
|
||||
@@ -104,7 +98,7 @@ let Oresp_hello(HS_DECL_ARGS, C_in:channel) =
|
||||
SES_EV( event InitiatorSession(rh, osk); )
|
||||
ic
|
||||
/* success */ ) in (
|
||||
out(C_in, Envelope(create_mac(spkt, IC2b(ic)), IC2b(ic)))
|
||||
out(C, ic)
|
||||
/* fail */ ) else (
|
||||
#if MESSAGE_TRANSMISSION_EVENTS
|
||||
event RHRjct(rh, psk, sski, spkr)
|
||||
@@ -122,28 +116,23 @@ MTX_EV( event IHRjct(InitHello_t, key, kem_sk, kem_pk). )
|
||||
MTX_EV( event RHSent(InitHello_t, RespHello_t, key, kem_sk, kem_pk). )
|
||||
event ConsumeSidr(SessionId, Atom).
|
||||
event ConsumeBn(Atom, kem_sk, kem_pk, Atom).
|
||||
|
||||
let Oinit_hello_inner(sidm:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt: kem_sk_tmpl, Septi: seed_tmpl, Sspti: seed_tmpl, ih: InitHello_t, C_out:channel) =
|
||||
let Oinit_hello() =
|
||||
in(C, Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih));
|
||||
#if RANDOMIZED_CALL_IDS
|
||||
new call:Atom;
|
||||
#else
|
||||
call <- Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih);
|
||||
#endif
|
||||
// TODO: This is ugly
|
||||
let InitHello(sidi, epki, sctr, pidiC, auth) = ih in
|
||||
|
||||
let InitHello(sidi, epki, sctr, pidi_ct, auth) = ih in
|
||||
SETUP_HANDSHAKE_STATE()
|
||||
|
||||
eski <- kem_sk0;
|
||||
|
||||
event ConsumeBn(biscuit_no, sskm, spkt, call);
|
||||
event ConsumeSidr(sidr, call);
|
||||
|
||||
epti <- rng_key(setup_seed(Septi)); // RHR4
|
||||
spti <- rng_key(setup_seed(Sspti)); // RHR5
|
||||
event ConsumeBn(biscuit_no, sskm, spkt, call);
|
||||
event ConsumeSidr(sidr, call);
|
||||
event ConsumeSeed(Epti, setup_seed(Septi), call);
|
||||
event ConsumeSeed(Spti, setup_seed(Sspti), call);
|
||||
|
||||
let rh = (
|
||||
INITHELLO_CONSUME()
|
||||
ck_ini <- ck;
|
||||
@@ -152,8 +141,7 @@ let Oinit_hello_inner(sidm:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:k
|
||||
MTX_EV( event RHSent(ih, rh, psk, sskr, spki); )
|
||||
rh
|
||||
/* success */ ) in (
|
||||
out(C_out, Envelope(create_mac(spkt, RH2b(rh)), RH2b(rh)))
|
||||
|
||||
out(C, rh)
|
||||
/* fail */ ) else (
|
||||
#if MESSAGE_TRANSMISSION_EVENTS
|
||||
event IHRjct(ih, psk, sskr, spki)
|
||||
@@ -162,10 +150,6 @@ let Oinit_hello_inner(sidm:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:k
|
||||
#endif
|
||||
).
|
||||
|
||||
let Oinit_hello() =
|
||||
in(C, Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih));
|
||||
Oinit_hello_inner(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih, C).
|
||||
|
||||
restriction sid:SessionId, ad1:Atom, ad2:Atom;
|
||||
event(ConsumeSidr(sid, ad1)) && event(ConsumeSidr(sid, ad2))
|
||||
==> ad1 = ad2.
|
||||
@@ -183,34 +167,26 @@ CK_EV( event OskOinitiator_ck(key). )
|
||||
CK_EV( event OskOinitiator(key, key, kem_sk, kem_pk, key). )
|
||||
MTX_EV( event IHSent(InitHello_t, key, kem_sk, kem_pk). )
|
||||
event ConsumeSidi(SessionId, Atom).
|
||||
|
||||
let Oinitiator_inner(sidi: SessionId, Ssskm: kem_sk_tmpl, Spsk: key_tmpl, Sspkt: kem_sk_tmpl, Seski: seed_tmpl, Ssptr: seed_tmpl, C_out:channel) =
|
||||
#if RANDOMIZED_CALL_IDS
|
||||
new call:Atom;
|
||||
#else
|
||||
call <- Cinitiator(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr);
|
||||
#endif
|
||||
|
||||
SETUP_HANDSHAKE_STATE()
|
||||
|
||||
sidr <- sid0;
|
||||
|
||||
RNG_KEM_PAIR(eski, epki, Seski) // IHI3
|
||||
sptr <- rng_key(setup_seed(Ssptr)); // IHI5
|
||||
event ConsumeSidi(sidi, call);
|
||||
event ConsumeSeed(Sptr, setup_seed(Ssptr), call);
|
||||
event ConsumeSeed(Eski, setup_seed(Seski), call);
|
||||
|
||||
INITHELLO_PRODUCE()
|
||||
CK_EV( event OskOinitiator_ck(ck); )
|
||||
CK_EV( event OskOinitiator(ck, psk, sski, spkr, sptr); )
|
||||
MTX_EV( event IHSent(ih, psk, sski, spkr); )
|
||||
out(C_out, Envelope(create_mac(spkt, IH2b(ih)), IH2b(ih)));
|
||||
Oresp_hello(HS_PASS_ARGS, C_out).
|
||||
|
||||
let Oinitiator() =
|
||||
in(C, Cinitiator(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr));
|
||||
Oinitiator_inner(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr, C).
|
||||
#if RANDOMIZED_CALL_IDS
|
||||
new call:Atom;
|
||||
#else
|
||||
call <- Cinitiator(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr);
|
||||
#endif
|
||||
SETUP_HANDSHAKE_STATE()
|
||||
RNG_KEM_PAIR(eski, epki, Seski) // IHI3
|
||||
sidr <- sid0;
|
||||
sptr <- rng_key(setup_seed(Ssptr)); // IHI5
|
||||
event ConsumeSidi(sidi, call);
|
||||
event ConsumeSeed(Sptr, setup_seed(Ssptr), call);
|
||||
event ConsumeSeed(Eski, setup_seed(Seski), call);
|
||||
INITHELLO_PRODUCE()
|
||||
CK_EV( event OskOinitiator_ck(ck); )
|
||||
CK_EV( event OskOinitiator(ck, psk, sski, spkr, sptr); )
|
||||
MTX_EV( event IHSent(ih, psk, sski, spkr); )
|
||||
out(C, ih);
|
||||
Oresp_hello(HS_PASS_ARGS).
|
||||
|
||||
restriction sid:SessionId, ad1:Atom, ad2:Atom;
|
||||
event(ConsumeSidi(sid, ad1)) && event(ConsumeSidi(sid, ad2))
|
||||
|
||||
@@ -2,39 +2,31 @@
|
||||
#include "crypto/kem.mpv"
|
||||
#include "rosenpass/handshake_state.mpv"
|
||||
|
||||
fun Envelope(
|
||||
key,
|
||||
bits
|
||||
): bits [data].
|
||||
letfun create_mac(pk:kem_pk, payload:bits) = lprf2(MAC, kem_pk2b(pk), payload).
|
||||
|
||||
type InitHello_t.
|
||||
fun InitHello(
|
||||
SessionId, // sidi
|
||||
kem_pk, // epki
|
||||
bits, // sctr
|
||||
bits, // pidiC
|
||||
bits, // pidi_ct
|
||||
bits // auth
|
||||
) : InitHello_t [data].
|
||||
|
||||
fun IH2b(InitHello_t) : bitstring [typeConverter].
|
||||
|
||||
#define INITHELLO_PRODUCE() \
|
||||
ck <- lprf1(CK_INIT, kem_pk2b(spkr)); /* IHI1 */ \
|
||||
/* not handled here */ /* IHI2 */ \
|
||||
/* not handled here */ /* IHI3 */ \
|
||||
MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHI4 */ \
|
||||
ENCAPS_AND_MIX(sctr, spkr, sptr) /* IHI5 */ \
|
||||
ENCRYPT_AND_MIX(pidiC, pidi) /* IHI6 */ \
|
||||
ENCRYPT_AND_MIX(pidi_ct, pidi) /* IHI6 */ \
|
||||
MIX2(kem_pk2b(spki), k2b(psk)) /* IHI7 */ \
|
||||
ENCRYPT_AND_MIX(auth, empty) /* IHI8 */ \
|
||||
ih <- InitHello(sidi, epki, sctr, pidiC, auth);
|
||||
ih <- InitHello(sidi, epki, sctr, pidi_ct, auth);
|
||||
|
||||
#define INITHELLO_CONSUME() \
|
||||
ck <- lprf1(CK_INIT, kem_pk2b(spkr)); /* IHR1 */ \
|
||||
MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHR4 */ \
|
||||
DECAPS_AND_MIX(sskr, spkr, sctr) /* IHR5 */ \
|
||||
DECRYPT_AND_MIX(pid, pidiC) /* IHR6 */ \
|
||||
DECRYPT_AND_MIX(pid, pidi_ct) /* IHR6 */ \
|
||||
LOOKUP_SENDER(pid) /* IHR6 */ \
|
||||
MIX2(kem_pk2b(spki), k2b(psk)) /* IHR7 */ \
|
||||
DECRYPT_AND_MIX(DUMMY(empty), auth)
|
||||
@@ -49,24 +41,22 @@ fun RespHello(
|
||||
bits // auth
|
||||
) : RespHello_t [data].
|
||||
|
||||
fun RH2b(RespHello_t) : bitstring [typeConverter].
|
||||
|
||||
#define RESPHELLO_PRODUCE() \
|
||||
#define RESPHELLO_PRODUCE() \
|
||||
/* not handled here */ /* RHR1 */ \
|
||||
MIX2(sid2b(sidr), sid2b(sidi)) /* RHR3 */ \
|
||||
ENCAPS_AND_MIX(ecti, epki, epti) /* RHR4 */ \
|
||||
ENCAPS_AND_MIX(scti, spki, spti) /* RHR5 */ \
|
||||
STORE_BISCUIT(biscuit) /* RHR6 */ \
|
||||
STORE_BISCUIT(biscuit_ct) /* RHR6 */ \
|
||||
ENCRYPT_AND_MIX(auth, empty) /* RHR7 */ \
|
||||
rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth);
|
||||
rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth);
|
||||
|
||||
#define RESPHELLO_CONSUME() \
|
||||
let RespHello(sidr, sidi, ecti, scti, biscuit, auth) = rh in \
|
||||
let RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth) = rh in \
|
||||
/* not handled here */ /* RHI2 */ \
|
||||
MIX2(sid2b(sidr), sid2b(sidi)) /* RHI3 */ \
|
||||
DECAPS_AND_MIX(eski, epki, ecti) /* RHI4 */ \
|
||||
DECAPS_AND_MIX(sski, spki, scti) /* RHI5 */ \
|
||||
MIX(biscuit) /* RHI6 */ \
|
||||
MIX(biscuit_ct) /* RHI6 */ \
|
||||
DECRYPT_AND_MIX(DUMMY(empty), auth) /* RHI7 */
|
||||
|
||||
type InitConf_t.
|
||||
@@ -77,16 +67,14 @@ fun InitConf(
|
||||
bits // auth
|
||||
) : InitConf_t [data].
|
||||
|
||||
fun IC2b(InitConf_t) : bitstring [typeConverter].
|
||||
|
||||
#define INITCONF_PRODUCE() \
|
||||
MIX2(sid2b(sidi), sid2b(sidr)) /* ICI3 */ \
|
||||
ENCRYPT_AND_MIX(auth, empty) /* ICI4 */ \
|
||||
ic <- InitConf(sidi, sidr, biscuit, auth);
|
||||
ic <- InitConf(sidi, sidr, biscuit_ct, auth);
|
||||
|
||||
#define INITCONF_CONSUME() \
|
||||
let InitConf(sidi, sidr, biscuit, auth) = ic in \
|
||||
LOAD_BISCUIT(biscuit_no, biscuit) /* ICR1 */ \
|
||||
let InitConf(sidi, sidr, biscuit_ct, auth) = ic in \
|
||||
LOAD_BISCUIT(biscuit_no, biscuit_ct)/* ICR1 */ \
|
||||
ENCRYPT_AND_MIX(rh_auth, empty) /* ICIR */ \
|
||||
ck_rh <- ck; /* ---- */ /* TODO: Move into oracles.mpv */ \
|
||||
MIX2(sid2b(sidi), sid2b(sidr)) /* ICR3 */ \
|
||||
|
||||
@@ -8,5 +8,13 @@ description = "Rosenpass internal traits for cryptographic primitives"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
rosenpass-to = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rosenpass-oqs = { workspace = true }
|
||||
rosenpass-secret-memory = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Rosenpass internal libsodium bindings
|
||||
# Rosenpass internal cryptographic traits
|
||||
|
||||
Rosenpass internal library providing traits for cryptographic primitives.
|
||||
|
||||
This is an internal library; not guarantee is made about its API at this point in time.
|
||||
This is an internal library; no guarantee is made about its API at this point in time.
|
||||
|
||||
137
cipher-traits/src/algorithms.rs
Normal file
137
cipher-traits/src/algorithms.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
//! This module contains the traits for all the cryptographic algorithms used throughout Rosenpass.
|
||||
//! These traits are marker traits that signal intent. They can also be used for trait objects.
|
||||
|
||||
/// Constants and trait for the Incorrect HMAC over Blake2b, with 256 key and hash length.
|
||||
pub mod keyed_hash_incorrect_hmac_blake2b {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashIncorrectHmacBlake2b`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashIncorrectHmacBlake2b`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is an incorrect HMAC over Blake2 (a custom Rosenpass construction)
|
||||
pub trait KeyedHashIncorrectHmacBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for Blake2b, with 256 key and hash length.
|
||||
pub mod keyed_hash_blake2b {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashBlake2b`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashBlake2b`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is Blake2b
|
||||
pub trait KeyedHashBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for SHAKE256, with 256 key and hash length.
|
||||
pub mod keyed_hash_shake256 {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashShake256`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashShake256`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is SHAKE256.
|
||||
pub trait KeyedHashShake256: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the ChaCha20Poly1305 AEAD
|
||||
pub mod aead_chacha20poly1305 {
|
||||
use crate::primitives::aead::*;
|
||||
|
||||
// See https://datatracker.ietf.org/doc/html/rfc7539#section-2.8
|
||||
|
||||
/// The key length used in [`AeadChaCha20Poly1305`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The nonce length used in [`AeadChaCha20Poly1305`].
|
||||
pub const NONCE_LEN: usize = 12;
|
||||
/// The tag length used in [`AeadChaCha20Poly1305`].
|
||||
pub const TAG_LEN: usize = 16;
|
||||
|
||||
/// An [`Aead`] that is ChaCha20Poly1305.
|
||||
pub trait AeadChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the XChaCha20Poly1305 AEAD (i.e. ChaCha20Poly1305 with extended nonce
|
||||
/// lengths)
|
||||
pub mod aead_xchacha20poly1305 {
|
||||
use crate::primitives::aead::*;
|
||||
|
||||
// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03
|
||||
|
||||
/// The key length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The nonce length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const NONCE_LEN: usize = 24;
|
||||
/// The tag length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const TAG_LEN: usize = 16;
|
||||
|
||||
/// An [`Aead`] that is XChaCha20Poly1305.
|
||||
pub trait AeadXChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the Kyber512 KEM
|
||||
pub mod kem_kyber512 {
|
||||
use crate::primitives::kem::*;
|
||||
|
||||
// page 39 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
|
||||
// (which is ml-kem instead of kyber, but it's the same)
|
||||
|
||||
/// The secret key length used in [`KemKyber512`].
|
||||
pub const SK_LEN: usize = 1632;
|
||||
|
||||
/// The public key length used in [`KemKyber512`].
|
||||
pub const PK_LEN: usize = 800;
|
||||
|
||||
/// The ciphertext length used in [`KemKyber512`].
|
||||
pub const CT_LEN: usize = 768;
|
||||
|
||||
/// The shared key length used in [`KemKyber512`].
|
||||
pub const SHK_LEN: usize = 32;
|
||||
|
||||
/// A [`Kem`] that is Kyber512.
|
||||
pub trait KemKyber512: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the Classic McEliece 460896 KEM
|
||||
pub mod kem_classic_mceliece460896 {
|
||||
use crate::primitives::kem::*;
|
||||
|
||||
// page 6 of https://classic.mceliece.org/mceliece-impl-20221023.pdf
|
||||
|
||||
/// The secret key length used in [`KemClassicMceliece460896`].
|
||||
pub const SK_LEN: usize = 13608;
|
||||
|
||||
/// The public key length used in [`KemClassicMceliece460896`].
|
||||
pub const PK_LEN: usize = 524160;
|
||||
|
||||
/// The ciphertext length used in [`KemClassicMceliece460896`].
|
||||
pub const CT_LEN: usize = 156;
|
||||
|
||||
/// The shared key length used in [`KemClassicMceliece460896`].
|
||||
pub const SHK_LEN: usize = 32;
|
||||
|
||||
/// A [`Kem`] that is ClassicMceliece460896.
|
||||
pub trait KemClassicMceliece460896: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
|
||||
}
|
||||
|
||||
pub use aead_chacha20poly1305::AeadChaCha20Poly1305;
|
||||
pub use aead_xchacha20poly1305::AeadXChaCha20Poly1305;
|
||||
|
||||
pub use kem_classic_mceliece460896::KemClassicMceliece460896;
|
||||
pub use kem_kyber512::KemKyber512;
|
||||
|
||||
pub use keyed_hash_blake2b::KeyedHashBlake2b;
|
||||
pub use keyed_hash_incorrect_hmac_blake2b::KeyedHashIncorrectHmacBlake2b;
|
||||
pub use keyed_hash_shake256::KeyedHashShake256;
|
||||
@@ -5,12 +5,128 @@
|
||||
//!
|
||||
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
|
||||
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
|
||||
//!
|
||||
//! encapsulation.
|
||||
//! The [KEM] Trait describes the basic API offered by a Key Encapsulation
|
||||
//! Mechanism. Two implementations for it are provided, [StaticKEM] and [EphemeralKEM].
|
||||
|
||||
use std::result::Result;
|
||||
//!
|
||||
//! The [Kem] Trait describes the basic API offered by a Key Encapsulation
|
||||
//! Mechanism. Two implementations for it are provided:
|
||||
//! [Kyber512](../../rosenpass_oqs/kyber_512/enum.Kyber512.html) and
|
||||
//! [ClassicMceliece460896](../../rosenpass_oqs/classic_mceliece_460896/enum.ClassicMceliece460896.html).
|
||||
//!
|
||||
//! An example where Alice generates a keypair and gives her public key to Bob, for Bob to
|
||||
//! encapsulate a symmetric key and Alice to decapsulate it would look as follows.
|
||||
//! In the example, we are using Kyber512, but any KEM that correctly implements the [Kem]
|
||||
//! trait could be used as well.
|
||||
//!```rust
|
||||
//! use rosenpass_cipher_traits::Kem;
|
||||
//! use rosenpass_oqs::Kyber512;
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//!
|
||||
//! type MyKem = Kyber512;
|
||||
//! secret_policy_use_only_malloc_secrets();
|
||||
//! let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! MyKem::keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! MyKem::encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! MyKem::decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//!
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//!```
|
||||
//!
|
||||
//! Implementing the [Kem]-trait for a KEM is easy. Mostly, you must format the KEM's
|
||||
//! keys, and ciphertext as `u8` slices. Below, we provide an example for how the trait can
|
||||
//! be implemented using a **HORRIBLY INSECURE** DummyKem that only uses static values for keys
|
||||
//! and ciphertexts as an example.
|
||||
//!```rust
|
||||
//!# use rosenpass_cipher_traits::Kem;
|
||||
//!
|
||||
//! struct DummyKem {}
|
||||
//! impl Kem for DummyKem {
|
||||
//!
|
||||
//! // For this DummyKem, using String for errors is sufficient.
|
||||
//! type Error = String;
|
||||
//!
|
||||
//! // For this DummyKem, we will use a single `u8` for everything
|
||||
//! const SK_LEN: usize = 1;
|
||||
//! const PK_LEN: usize = 1;
|
||||
//! const CT_LEN: usize = 1;
|
||||
//! const SHK_LEN: usize = 1;
|
||||
//!
|
||||
//! fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Result<(), Self::Error> {
|
||||
//! if sk.len() != Self::SK_LEN {
|
||||
//! return Err("sk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if pk.len() != Self::PK_LEN {
|
||||
//! return Err("pk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! sk[0] = 42;
|
||||
//! pk[0] = 21;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Result<(), Self::Error> {
|
||||
//! if pk.len() != Self::PK_LEN {
|
||||
//! return Err("pk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if ct.len() != Self::CT_LEN {
|
||||
//! return Err("ct does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if shk.len() != Self::SHK_LEN {
|
||||
//! return Err("shk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if pk[0] != 21 {
|
||||
//! return Err("Invalid public key!".to_string());
|
||||
//! }
|
||||
//! ct[0] = 7;
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Result<(), Self::Error> {
|
||||
//! if sk.len() != Self::SK_LEN {
|
||||
//! return Err("sk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if ct.len() != Self::CT_LEN {
|
||||
//! return Err("ct does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if shk.len() != Self::SHK_LEN {
|
||||
//! return Err("shk does not have the correct length!".to_string());
|
||||
//! }
|
||||
//! if sk[0] != 42 {
|
||||
//! return Err("Invalid public key!".to_string());
|
||||
//! }
|
||||
//! if ct[0] != 7 {
|
||||
//! return Err("Invalid ciphertext!".to_string());
|
||||
//! }
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//! #
|
||||
//! # type MyKem = DummyKem;
|
||||
//! # secret_policy_use_only_malloc_secrets();
|
||||
//! # let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! # let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! # MyKem::keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! # let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! # MyKem::encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//! #
|
||||
//! # let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # MyKem::decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//! #
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! #
|
||||
//! # Ok::<(), String>(())
|
||||
//!```
|
||||
//!
|
||||
|
||||
/// Key Encapsulation Mechanism
|
||||
///
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
mod kem;
|
||||
pub use kem::Kem;
|
||||
//! This trait contains traits, constants and wrappers that provid= the interface between Rosenpass
|
||||
//! as a consumer of cryptographic libraries and the implementations of cryptographic algorithms.
|
||||
|
||||
pub mod algorithms;
|
||||
pub mod primitives;
|
||||
|
||||
10
cipher-traits/src/primitives.rs
Normal file
10
cipher-traits/src/primitives.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
//! Traits for cryptographic primitives used in Rosenpass, specifically KEM, AEAD and keyed
|
||||
//! hashing.
|
||||
|
||||
pub(crate) mod aead;
|
||||
pub(crate) mod kem;
|
||||
pub(crate) mod keyed_hash;
|
||||
|
||||
pub use aead::{Aead, AeadWithNonceInCiphertext, Error as AeadError};
|
||||
pub use kem::{Error as KemError, Kem};
|
||||
pub use keyed_hash::*;
|
||||
175
cipher-traits/src/primitives/aead.rs
Normal file
175
cipher-traits/src/primitives/aead.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
use rosenpass_to::{ops::copy_slice, To as _};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Models authenticated encryption with assiciated data (AEAD) functionality.
|
||||
///
|
||||
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
|
||||
/// 1. It makes type inference a lot smoother
|
||||
/// 2. It allows to use the functionality through a trait object or having an enum that has
|
||||
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
|
||||
///
|
||||
/// Since the caller needs an instance of the type to use the functionality, implementors are
|
||||
/// adviced to implement the [`Default`] trait where possible.
|
||||
///
|
||||
/// Example for encrypting a message with a specific [`Aead`] instance:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Aead;
|
||||
///
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const NONCE_LEN: usize = 12;
|
||||
/// const TAG_LEN: usize = 16;
|
||||
///
|
||||
/// fn encrypt_message_given_an_aead<AeadImpl>(
|
||||
/// aead: &AeadImpl,
|
||||
/// msg: &str,
|
||||
/// nonce: &[u8; NONCE_LEN],
|
||||
/// encrypted: &mut [u8]
|
||||
/// ) where AeadImpl: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
|
||||
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
|
||||
/// let ad = b""; // we don't need associated data here
|
||||
/// aead.encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If only the type (but no instance) is available, then we can still encrypt, as long as the type
|
||||
/// also is [`Default`]:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Aead;
|
||||
///
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const NONCE_LEN: usize = 12;
|
||||
/// const TAG_LEN: usize = 16;
|
||||
///
|
||||
/// fn encrypt_message_without_aead<AeadImpl>(
|
||||
/// msg: &str,
|
||||
/// nonce: &[u8; NONCE_LEN],
|
||||
/// encrypted: &mut [u8]
|
||||
/// ) where AeadImpl: Default + Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
|
||||
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
|
||||
/// let ad = b""; // we don't need associated data here
|
||||
/// AeadImpl::default().encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Aead<const KEY_LEN: usize, const NONCE_LEN: usize, const TAG_LEN: usize> {
|
||||
const KEY_LEN: usize = KEY_LEN;
|
||||
const NONCE_LEN: usize = NONCE_LEN;
|
||||
const TAG_LEN: usize = TAG_LEN;
|
||||
|
||||
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `ciphertext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `plaintext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Provides an AEAD API where the nonce is part of the ciphertext.
|
||||
///
|
||||
/// The old xaead API had the ciphertext begin with the `nonce`. In order to not having to change
|
||||
/// the calling code too much, we add a wrapper trait that provides this API and implement it for
|
||||
/// all AEAD.
|
||||
pub trait AeadWithNonceInCiphertext<
|
||||
const KEY_LEN: usize,
|
||||
const NONCE_LEN: usize,
|
||||
const TAG_LEN: usize,
|
||||
>: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>
|
||||
{
|
||||
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `ciphertext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
|
||||
fn encrypt_with_nonce_in_ctxt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < NONCE_LEN + TAG_LEN
|
||||
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
|
||||
{
|
||||
return Err(Error::InvalidLengths);
|
||||
}
|
||||
|
||||
let (n, rest) = ciphertext.split_at_mut(NONCE_LEN);
|
||||
copy_slice(nonce).to(n);
|
||||
|
||||
self.encrypt(rest, key, nonce, ad, plaintext)
|
||||
}
|
||||
|
||||
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `plaintext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
|
||||
fn decrypt_with_nonce_in_ctxt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < NONCE_LEN + TAG_LEN
|
||||
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
|
||||
{
|
||||
return Err(Error::InvalidLengths);
|
||||
}
|
||||
|
||||
let (nonce, rest) = ciphertext.split_at(NONCE_LEN);
|
||||
// We know this should be the right length (we just split it), and everything else would be
|
||||
// very unexpected.
|
||||
let nonce = nonce.try_into().map_err(|_| Error::InternalError)?;
|
||||
|
||||
self.decrypt(plaintext, key, nonce, ad, rest)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
const KEY_LEN: usize,
|
||||
const NONCE_LEN: usize,
|
||||
const TAG_LEN: usize,
|
||||
T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>,
|
||||
> AeadWithNonceInCiphertext<KEY_LEN, NONCE_LEN, TAG_LEN> for T
|
||||
{
|
||||
}
|
||||
|
||||
/// The error returned by AEAD operations
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// An internal error occurred. This should never be happen and indicates an error in the
|
||||
/// AEAD implementation.
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Could not decrypt a message because the message is not a valid ciphertext for the given
|
||||
/// key.
|
||||
#[error("decryption error")]
|
||||
DecryptError,
|
||||
|
||||
/// The provided buffers have the wrong lengths.
|
||||
#[error("buffers have invalid length")]
|
||||
InvalidLengths,
|
||||
}
|
||||
212
cipher-traits/src/primitives/kem.rs
Normal file
212
cipher-traits/src/primitives/kem.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
//! Traits and implementations for Key Encapsulation Mechanisms (KEMs)
|
||||
//!
|
||||
//! KEMs are the interface provided by almost all post-quantum
|
||||
//! secure key exchange mechanisms.
|
||||
//!
|
||||
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
|
||||
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
|
||||
//! encapsulation.
|
||||
//!
|
||||
//! The [Kem] Trait describes the basic API offered by a Key Encapsulation
|
||||
//! Mechanism. Two implementations for it are provided:
|
||||
//! [Kyber512](../../rosenpass_oqs/kyber_512/enum.Kyber512.html) and
|
||||
//! [ClassicMceliece460896](../../rosenpass_oqs/classic_mceliece_460896/enum.ClassicMceliece460896.html).
|
||||
//!
|
||||
//! An example where Alice generates a keypair and gives her public key to Bob, for Bob to
|
||||
//! encapsulate a symmetric key and Alice to decapsulate it would look as follows.
|
||||
//! In the example, we are using Kyber512, but any KEM that correctly implements the [Kem]
|
||||
//! trait could be used as well.
|
||||
//!```rust
|
||||
//! use rosenpass_cipher_traits::primitives::Kem;
|
||||
//! use rosenpass_oqs::Kyber512;
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//!
|
||||
//! type MyKem = Kyber512;
|
||||
//! secret_policy_use_only_malloc_secrets();
|
||||
//! let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//!
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//!```
|
||||
//!
|
||||
//! Implementing the [Kem]-trait for a KEM is easy. Mostly, you must format the KEM's
|
||||
//! keys, and ciphertext as `u8` slices. Below, we provide an example for how the trait can
|
||||
//! be implemented using a **HORRIBLY INSECURE** DummyKem that only uses static values for keys
|
||||
//! and ciphertexts as an example.
|
||||
//!```rust
|
||||
//!# use rosenpass_cipher_traits::primitives::{Kem, KemError as Error};
|
||||
//!
|
||||
//! struct DummyKem {}
|
||||
//! impl Kem<1,1,1,1> for DummyKem {
|
||||
//!
|
||||
//! // For this DummyKem, we will use a single `u8` for everything
|
||||
//! const SK_LEN: usize = 1;
|
||||
//! const PK_LEN: usize = 1;
|
||||
//! const CT_LEN: usize = 1;
|
||||
//! const SHK_LEN: usize = 1;
|
||||
//!
|
||||
//! fn keygen(&self, sk: &mut [u8;1], pk: &mut [u8;1]) -> Result<(), Error> {
|
||||
//! sk[0] = 42;
|
||||
//! pk[0] = 21;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn encaps(&self, shk: &mut [u8;1], ct: &mut [u8;1], pk: &[u8;1]) -> Result<(), Error> {
|
||||
//! if pk[0] != 21 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! ct[0] = 7;
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn decaps(&self, shk: &mut [u8;1 ], sk: &[u8;1], ct: &[u8;1]) -> Result<(), Error> {
|
||||
//! if sk[0] != 42 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! if ct[0] != 7 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl Default for DummyKem {
|
||||
//! fn default() -> Self {
|
||||
//! Self{}
|
||||
//! }
|
||||
//! }
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//! #
|
||||
//! # type MyKem = DummyKem;
|
||||
//! # secret_policy_use_only_malloc_secrets();
|
||||
//! # let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! # let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! # MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! # let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! # MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//! #
|
||||
//! # let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//! #
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! #
|
||||
//! # Ok::<(), Error>(())
|
||||
//!```
|
||||
//!
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Key Encapsulation Mechanism
|
||||
///
|
||||
/// The KEM interface defines three operations: Key generation, key encapsulation and key
|
||||
/// decapsulation. The parameters are made available as associated constants for convenience.
|
||||
///
|
||||
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
|
||||
/// 1. It makes type inference a lot smoother
|
||||
/// 2. It allows to use the functionality through a trait object or having an enum that has
|
||||
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
|
||||
///
|
||||
/// Since the caller needs an instance of the type to use the functionality, implementors are
|
||||
/// adviced to implement the [`Default`] trait where possible.
|
||||
///
|
||||
/// Example for encrypting a message with a specific [`Kem`] instance:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Kem;
|
||||
///
|
||||
/// const SK_LEN: usize = 1632;
|
||||
/// const PK_LEN: usize = 800;
|
||||
/// const CT_LEN: usize = 768;
|
||||
/// const SHK_LEN: usize = 32;
|
||||
///
|
||||
/// fn encaps_given_a_kem<KemImpl>(
|
||||
/// kem: &KemImpl,
|
||||
/// pk: &[u8; PK_LEN],
|
||||
/// ct: &mut [u8; CT_LEN]
|
||||
/// ) -> [u8; SHK_LEN] where KemImpl: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>{
|
||||
/// let mut shk = [0u8; SHK_LEN];
|
||||
/// kem.encaps(&mut shk, ct, pk).unwrap();
|
||||
/// shk
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If only the type (but no instance) is available, then we can still use the trait, as long as
|
||||
/// the type also is [`Default`]:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Kem;
|
||||
///
|
||||
/// const SK_LEN: usize = 1632;
|
||||
/// const PK_LEN: usize = 800;
|
||||
/// const CT_LEN: usize = 768;
|
||||
/// const SHK_LEN: usize = 32;
|
||||
///
|
||||
/// fn encaps_without_kem<KemImpl>(
|
||||
/// pk: &[u8; PK_LEN],
|
||||
/// ct: &mut [u8; CT_LEN]
|
||||
/// ) -> [u8; SHK_LEN]
|
||||
/// where KemImpl: Default + Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {
|
||||
/// let mut shk = [0u8; SHK_LEN];
|
||||
/// KemImpl::default().encaps(&mut shk, ct, pk).unwrap();
|
||||
/// shk
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Kem<const SK_LEN: usize, const PK_LEN: usize, const CT_LEN: usize, const SHK_LEN: usize> {
|
||||
/// The length of the secret (decapsulation) key.
|
||||
const SK_LEN: usize = SK_LEN;
|
||||
|
||||
/// The length of the public (encapsulation) key.
|
||||
const PK_LEN: usize = PK_LEN;
|
||||
|
||||
/// The length of the ciphertext.
|
||||
const CT_LEN: usize = CT_LEN;
|
||||
|
||||
/// The legnth of the resulting shared key.
|
||||
const SHK_LEN: usize = SHK_LEN;
|
||||
|
||||
/// Generate a keypair consisting of secret key (`sk`) and public key (`pk`)
|
||||
///
|
||||
/// `keygen() -> sk, pk`
|
||||
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), Error>;
|
||||
|
||||
/// From a public key (`pk`), generate a shared key (`shk`, for local use)
|
||||
/// and a cipher text (`ct`, to be sent to the owner of the `pk`).
|
||||
///
|
||||
/// `encaps(pk) -> shk, ct`
|
||||
fn encaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
ct: &mut [u8; CT_LEN],
|
||||
pk: &[u8; PK_LEN],
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// From a secret key (`sk`) and a cipher text (`ct`) derive a shared key
|
||||
/// (`shk`)
|
||||
///
|
||||
/// `decaps(sk, ct) -> shk`
|
||||
fn decaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
sk: &[u8; SK_LEN],
|
||||
ct: &[u8; CT_LEN],
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("invalid argument")]
|
||||
InvalidArgument,
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
}
|
||||
159
cipher-traits/src/primitives/keyed_hash.rs
Normal file
159
cipher-traits/src/primitives/keyed_hash.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Models a keyed hash function using an associated function (i.e. without `&self` receiver).
|
||||
pub trait KeyedHash<const KEY_LEN: usize, const HASH_LEN: usize> {
|
||||
/// The error type used to signal what went wrong.
|
||||
type Error;
|
||||
|
||||
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Models a keyed hash function using a method (i.e. with a `&self` receiver).
|
||||
///
|
||||
/// This makes type inference easier, but also requires having a [`KeyedHashInstance`] value,
|
||||
/// instead of just the [`KeyedHash`] type.
|
||||
pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
|
||||
/// The error type used to signal what went wrong.
|
||||
type Error;
|
||||
|
||||
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// This is a helper to allow for type parameter inference when calling functions
|
||||
/// that need a [KeyedHash].
|
||||
///
|
||||
/// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable
|
||||
/// can be used for type inference. Less typing work.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub _phantom_keyed_hasher: PhantomData<Static>,
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub const KEY_LEN: usize = KEY_LEN;
|
||||
pub const HASH_LEN: usize = HASH_LEN;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
_phantom_keyed_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
|
||||
fn keyed_hash_internal<'a>(
|
||||
&self,
|
||||
key: &'a [u8; KEY_LEN],
|
||||
data: &'a [u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
Static::keyed_hash(key, data, out)
|
||||
}
|
||||
|
||||
/// Returns the key length of the keyed hash function.
|
||||
pub const fn key_len(self) -> usize {
|
||||
Self::KEY_LEN
|
||||
}
|
||||
|
||||
/// Returns the hash length of the keyed hash function.
|
||||
pub const fn hash_len(self) -> usize {
|
||||
Self::HASH_LEN
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = Static::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
self.keyed_hash_internal(key, data, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper traits /////////////////////////////////////////////
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
}
|
||||
|
||||
use rosenpass_to::{with_destination, To};
|
||||
|
||||
/// Extends the [`KeyedHash`] trait with a [`To`]-flavoured function.
|
||||
pub trait KeyedHashTo<const KEY_LEN: usize, const HASH_LEN: usize>:
|
||||
KeyedHash<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
fn keyed_hash_to(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
|
||||
with_destination(|out| Self::keyed_hash(key, data, out))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHash<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashTo<KEY_LEN, HASH_LEN> for T
|
||||
{
|
||||
}
|
||||
|
||||
/// Extends the [`KeyedHashInstance`] trait with a [`To`]-flavoured function.
|
||||
pub trait KeyedHashInstanceTo<const KEY_LEN: usize, const HASH_LEN: usize>:
|
||||
KeyedHashInstance<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
fn keyed_hash_to(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
|
||||
with_destination(|out| self.keyed_hash(key, data, out))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHashInstance<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashInstanceTo<KEY_LEN, HASH_LEN> for T
|
||||
{
|
||||
}
|
||||
@@ -8,6 +8,42 @@ description = "Rosenpass internal ciphers and other cryptographic primitives use
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
# whether the types should be defined
|
||||
experiment_libcrux_define_blake2 = ["dep:libcrux-blake2", "dep:thiserror"]
|
||||
experiment_libcrux_define_kyber = ["dep:libcrux-ml-kem", "dep:rand"]
|
||||
experiment_libcrux_define_chachapoly = ["dep:libcrux-chacha20poly1305"]
|
||||
|
||||
# whether the types should be used by default
|
||||
experiment_libcrux_blake2 = ["experiment_libcrux_define_blake2"]
|
||||
experiment_libcrux_kyber = ["experiment_libcrux_define_kyber"]
|
||||
experiment_libcrux_chachapoly = ["experiment_libcrux_define_chachapoly"]
|
||||
experiment_libcrux_chachapoly_test = [
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"dep:libcrux",
|
||||
]
|
||||
|
||||
# shorthands
|
||||
experiment_libcrux_define_all = [
|
||||
"experiment_libcrux_define_blake2",
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"experiment_libcrux_define_kyber",
|
||||
]
|
||||
experiment_libcrux_all = [
|
||||
"experiment_libcrux_blake2",
|
||||
"experiment_libcrux_chachapoly",
|
||||
"experiment_libcrux_chachapoly_test",
|
||||
"experiment_libcrux_kyber",
|
||||
]
|
||||
|
||||
bench = ["experiment_libcrux_define_all"]
|
||||
|
||||
[[bench]]
|
||||
name = "primitives"
|
||||
harness = false
|
||||
required-features = ["bench"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
@@ -16,7 +52,22 @@ rosenpass-constant-time = { workspace = true }
|
||||
rosenpass-secret-memory = { workspace = true }
|
||||
rosenpass-oqs = { workspace = true }
|
||||
rosenpass-util = { workspace = true }
|
||||
rosenpass-cipher-traits = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
chacha20poly1305 = { workspace = true }
|
||||
blake2 = { workspace = true }
|
||||
sha3 = { workspace = true }
|
||||
rand = { workspace = true, optional = true }
|
||||
thiserror = { workspace = true, optional = true }
|
||||
|
||||
libcrux-chacha20poly1305 = { workspace = true, optional = true }
|
||||
libcrux-blake2 = { workspace = true, optional = true }
|
||||
libcrux-ml-kem = { workspace = true, optional = true, features = ["kyber"] }
|
||||
|
||||
# this one is only used in testing, so it requires the `experiment_libcrux_chachapoly_test` feature.
|
||||
libcrux = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
criterion = { workspace = true }
|
||||
|
||||
378
ciphers/benches/primitives.rs
Normal file
378
ciphers/benches/primitives.rs
Normal file
@@ -0,0 +1,378 @@
|
||||
criterion::criterion_main!(keyed_hash::benches, aead::benches, kem::benches);
|
||||
|
||||
fn benchid(base: KvPairs, last: KvPairs) -> String {
|
||||
format!("{base},{last}")
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPair<'a>(&'a str, &'a str);
|
||||
|
||||
impl std::fmt::Display for KvPair<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{k}={v}", k = self.0, v = self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPairs<'a>(&'a [KvPair<'a>]);
|
||||
|
||||
impl std::fmt::Display for KvPairs<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.0.len() {
|
||||
0 => Ok(()),
|
||||
1 => write!(f, "{}", &self.0[0]),
|
||||
_ => {
|
||||
let mut delim = "";
|
||||
for pair in self.0 {
|
||||
write!(f, "{delim}{pair}")?;
|
||||
delim = ",";
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod kem {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_kyber512_libcrux,
|
||||
bench_kyber512_oqs,
|
||||
bench_classicmceliece460896_oqs
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_classicmceliece460896_oqs(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"classicmceliece460896",
|
||||
"oqs",
|
||||
rosenpass_oqs::ClassicMceliece460896,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"kyber512",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::kyber512::Kyber512,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_oqs(c: &mut Criterion) {
|
||||
template(c, "kyber512", "oqs", rosenpass_oqs::Kyber512);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
|
||||
fn template<
|
||||
const SK_LEN: usize,
|
||||
const PK_LEN: usize,
|
||||
const CT_LEN: usize,
|
||||
const SHK_LEN: usize,
|
||||
T: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>,
|
||||
>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use super::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "kem"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("length", "-1"),
|
||||
];
|
||||
|
||||
let kem_benchid = |op| benchid(KvPairs(&base), KvPairs(&[KvPair("operation", op)]));
|
||||
|
||||
c.bench_function(&kem_benchid("keygen"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("encaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("decaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
let mut shk2 = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.decaps(&mut shk2, &sk, &ct).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
mod aead {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_chachapoly_libcrux,
|
||||
bench_chachapoly_rustcrypto,
|
||||
bench_xchachapoly_rustcrypto,
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
const KEY_LEN: usize = rosenpass_ciphers::Aead::KEY_LEN;
|
||||
const TAG_LEN: usize = rosenpass_ciphers::Aead::TAG_LEN;
|
||||
|
||||
fn bench_xchachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"xchacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Aead;
|
||||
|
||||
fn template<const NONCE_LEN: usize, T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "aead"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
];
|
||||
let aead_benchid = |op, len| {
|
||||
benchid(
|
||||
KvPairs(&base),
|
||||
KvPairs(&[KvPair("operation", op), KvPair("length", len)]),
|
||||
)
|
||||
};
|
||||
|
||||
let key = [12; KEY_LEN];
|
||||
let nonce = [23; NONCE_LEN];
|
||||
let ad = [];
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
c.bench_function(&aead_benchid("decrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod keyed_hash {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_blake2b_rustcrypto,
|
||||
bench_blake2b_libcrux,
|
||||
bench_shake256_rustcrypto,
|
||||
);
|
||||
|
||||
const KEY_LEN: usize = 32;
|
||||
const HASH_LEN: usize = 32;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_shake256_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"shake256",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"libcrux",
|
||||
&rosenpass_ciphers::subtle::libcrux::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
|
||||
fn template<H: KeyedHash<KEY_LEN, HASH_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
_: &H,
|
||||
) where
|
||||
H::Error: std::fmt::Debug,
|
||||
{
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let key = [12u8; KEY_LEN];
|
||||
let mut out = [0u8; HASH_LEN];
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "keyedhash"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("operation", "hash"),
|
||||
];
|
||||
let keyedhash_benchid = |len| benchid(KvPairs(&base), KvPairs(&[KvPair("length", len)]));
|
||||
|
||||
c.bench_function(&keyedhash_benchid("0byte"), |bench| {
|
||||
let bytes = [];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("32byte"), |bench| {
|
||||
let bytes = [34u8; 32];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("64byte"), |bench| {
|
||||
let bytes = [34u8; 64];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("128byte"), |bench| {
|
||||
let bytes = [34u8; 128];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("1024byte"), |bench| {
|
||||
let bytes = [34u8; 1024];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,109 +1,276 @@
|
||||
//!
|
||||
//!```rust
|
||||
//! # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
|
||||
//! use rosenpass_ciphers::KeyedHash;
|
||||
//! use rosenpass_secret_memory::Secret;
|
||||
//! # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
|
||||
//!
|
||||
//! const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
|
||||
//! // create use once hash domain for the protocol identifier
|
||||
//! let mut hash_domain = HashDomain::zero(KeyedHash::keyed_shake256());
|
||||
//! hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
|
||||
//! // upgrade to reusable hash domain
|
||||
//! let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
|
||||
//! // derive new key
|
||||
//! let key_identifier = "my_key_identifier";
|
||||
//! let key = hash_domain_namespace.mix(key_identifier.as_bytes())?.into_value();
|
||||
//! // derive a new key based on a secret
|
||||
//! const MY_SECRET_LEN: usize = 21;
|
||||
//! let my_secret_bytes = "my super duper secret".as_bytes();
|
||||
//! let my_secret: Secret<21> = Secret::from_slice("my super duper secret".as_bytes());
|
||||
//! let secret_hash_domain: SecretHashDomain = hash_domain_namespace.mix_secret(my_secret)?;
|
||||
//! // derive a new key based on the secret key
|
||||
//! let new_key_identifier = "my_new_key_identifier".as_bytes();
|
||||
//! let new_key = secret_hash_domain.mix(new_key_identifier)?.into_secret();
|
||||
//!
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//!```
|
||||
//!
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_to::To;
|
||||
use rosenpass_to::To as _;
|
||||
|
||||
use crate::subtle::incorrect_hmac_blake2b as hash;
|
||||
pub use crate::{KeyedHash, KEY_LEN};
|
||||
|
||||
pub use hash::KEY_LEN;
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashInstanceTo;
|
||||
|
||||
// TODO Use a proper Dec interface
|
||||
/// A use-once hash domain for a specified key that can be used directly.
|
||||
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
|
||||
/// use [SecretHashDomain] instead.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HashDomain([u8; KEY_LEN]);
|
||||
pub struct HashDomain([u8; KEY_LEN], KeyedHash);
|
||||
/// A reusable hash domain for a namespace identified by the key.
|
||||
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
|
||||
/// use [SecretHashDomainNamespace] instead.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HashDomainNamespace([u8; KEY_LEN]);
|
||||
pub struct HashDomainNamespace([u8; KEY_LEN], KeyedHash);
|
||||
/// A use-once hash domain for a specified key that can be used directly
|
||||
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SecretHashDomain(Secret<KEY_LEN>);
|
||||
pub struct SecretHashDomain(Secret<KEY_LEN>, KeyedHash);
|
||||
/// A reusable secure hash domain for a namespace identified by the key and that keeps the key secure
|
||||
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>);
|
||||
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>, KeyedHash);
|
||||
|
||||
impl HashDomain {
|
||||
pub fn zero() -> Self {
|
||||
Self([0u8; KEY_LEN])
|
||||
/// Creates a nw [HashDomain] initialized with a all-zeros key.
|
||||
pub fn zero(choice: KeyedHash) -> Self {
|
||||
Self([0u8; KEY_LEN], choice)
|
||||
}
|
||||
|
||||
/// Turns this [HashDomain] into a [HashDomainNamespace], keeping the key.
|
||||
pub fn dup(self) -> HashDomainNamespace {
|
||||
HashDomainNamespace(self.0)
|
||||
HashDomainNamespace(self.0, self.1)
|
||||
}
|
||||
|
||||
/// Turns this [HashDomain] into a [SecretHashDomain] by wrapping the key into a [Secret]
|
||||
/// and creating a new [SecretHashDomain] from it.
|
||||
pub fn turn_secret(self) -> SecretHashDomain {
|
||||
SecretHashDomain(Secret::from_slice(&self.0))
|
||||
SecretHashDomain(Secret::from_slice(&self.0), self.1)
|
||||
}
|
||||
|
||||
// TODO: Protocol! Use domain separation to ensure that
|
||||
/// Creates a new [HashDomain] by mixing in a new key `v`. Specifically,
|
||||
/// it evaluates [hash::hash] with this HashDomain's key as the key and `v`
|
||||
/// as the `data` and uses the result as the key for the new [HashDomain].
|
||||
///
|
||||
pub fn mix(self, v: &[u8]) -> Result<Self> {
|
||||
Ok(Self(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?))
|
||||
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
|
||||
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
|
||||
Ok(Self(new_key, self.1))
|
||||
}
|
||||
|
||||
/// Version of [Self::mix] that accepts an iterator and mixes all values from the iterator into
|
||||
/// this hash domain.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass_ciphers::{hash_domain::HashDomain, KeyedHash};
|
||||
///
|
||||
/// let hasher = HashDomain::zero(KeyedHash::keyed_shake256());
|
||||
/// assert_eq!(
|
||||
/// hasher.clone().mix(b"Hello")?.mix(b"World")?.into_value(),
|
||||
/// hasher.clone().mix_many([b"Hello", b"World"])?.into_value()
|
||||
/// );
|
||||
///
|
||||
/// Ok::<(), anyhow::Error>(())
|
||||
/// ```
|
||||
pub fn mix_many<I, T>(mut self, it: I) -> Result<Self>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
for e in it {
|
||||
self = self.mix(e.as_ref())?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
/// by calling [SecretHashDomain::invoke_primitive] with this
|
||||
/// [HashDomain]'s key as `k` and `v` as `d`.
|
||||
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret())
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1)
|
||||
}
|
||||
|
||||
/// Gets the key of this [HashDomain].
|
||||
pub fn into_value(self) -> [u8; KEY_LEN] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl HashDomainNamespace {
|
||||
/// Creates a new [HashDomain] by mixing in a new key `v`. Specifically,
|
||||
/// it evaluates [hash::hash] with the key of this HashDomainNamespace key as the key and `v`
|
||||
/// as the `data` and uses the result as the key for the new [HashDomain].
|
||||
pub fn mix(&self, v: &[u8]) -> Result<HashDomain> {
|
||||
Ok(HashDomain(
|
||||
hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?,
|
||||
))
|
||||
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
|
||||
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
|
||||
Ok(HashDomain(new_key, self.1.clone()))
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
/// by calling [SecretHashDomain::invoke_primitive] with the key of this
|
||||
/// [HashDomainNamespace] as `k` and `v` as `d`.
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret())
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretHashDomain {
|
||||
pub fn invoke_primitive(k: &[u8], d: &[u8]) -> Result<SecretHashDomain> {
|
||||
let mut r = SecretHashDomain(Secret::zero());
|
||||
hash::hash(k, d).to(r.0.secret_mut())?;
|
||||
/// Create a new [SecretHashDomain] with the given key `k` and data `d` by calling
|
||||
/// [hash::hash] with `k` as the `key` and `d` s the `data`, and using the result
|
||||
/// as the content for the new [SecretHashDomain].
|
||||
/// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length.
|
||||
/// TODO: docu
|
||||
pub fn invoke_primitive(
|
||||
k: &[u8],
|
||||
d: &[u8],
|
||||
hash_choice: KeyedHash,
|
||||
) -> Result<SecretHashDomain> {
|
||||
let mut new_secret_key = Secret::zero();
|
||||
hash_choice
|
||||
.keyed_hash_to(k.try_into()?, d)
|
||||
.to(new_secret_key.secret_mut())?;
|
||||
let r = SecretHashDomain(new_secret_key, hash_choice);
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self(Secret::zero())
|
||||
/// Creates a new [SecretHashDomain] that is initialized with an all zeros key.
|
||||
pub fn zero(hash_choice: KeyedHash) -> Self {
|
||||
Self(Secret::zero(), hash_choice)
|
||||
}
|
||||
|
||||
/// Turns this [SecretHashDomain] into a [SecretHashDomainNamespace].
|
||||
pub fn dup(self) -> SecretHashDomainNamespace {
|
||||
SecretHashDomainNamespace(self.0)
|
||||
SecretHashDomainNamespace(self.0, self.1)
|
||||
}
|
||||
|
||||
pub fn danger_from_secret(k: Secret<KEY_LEN>) -> Self {
|
||||
Self(k)
|
||||
/// Creates a new [SecretHashDomain] from a [Secret] `k`.
|
||||
///
|
||||
/// It requires that `k` consist of exactly [KEY_LEN] bytes.
|
||||
pub fn danger_from_secret(k: Secret<KEY_LEN>, hash_choice: KeyedHash) -> Self {
|
||||
Self(k, hash_choice)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`. Specifically,
|
||||
/// it evaluates [hash::hash] with this [SecretHashDomain]'s key as the key and `v`
|
||||
/// as the `data` and uses the result as the key for the new [SecretHashDomain].
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix(self, v: &[u8]) -> Result<SecretHashDomain> {
|
||||
Self::invoke_primitive(self.0.secret(), v)
|
||||
Self::invoke_primitive(self.0.secret(), v, self.1)
|
||||
}
|
||||
|
||||
/// Version of [Self::mix] that accepts an iterator and mixes all values from the iterator into
|
||||
/// this hash domain.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass_ciphers::{hash_domain::HashDomain, KeyedHash};
|
||||
///
|
||||
/// rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
/// let hasher = HashDomain::zero(KeyedHash::keyed_shake256());
|
||||
/// assert_eq!(
|
||||
/// hasher
|
||||
/// .clone()
|
||||
/// .turn_secret()
|
||||
/// .mix(b"Hello")?
|
||||
/// .mix(b"World")?
|
||||
/// .into_secret()
|
||||
/// .secret(),
|
||||
/// hasher
|
||||
/// .clone()
|
||||
/// .turn_secret()
|
||||
/// .mix_many([b"Hello", b"World"])?
|
||||
/// .into_secret()
|
||||
/// .secret(),
|
||||
/// );
|
||||
|
||||
/// Ok::<(), anyhow::Error>(())
|
||||
/// ```
|
||||
pub fn mix_many<I, T>(mut self, it: I) -> Result<Self>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
for e in it {
|
||||
self = self.mix(e.as_ref())?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
/// by calling [SecretHashDomain::invoke_primitive] with the key of this
|
||||
/// [HashDomainNamespace] as `k` and `v` as `d`.
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
Self::invoke_primitive(self.0.secret(), v.secret())
|
||||
Self::invoke_primitive(self.0.secret(), v.secret(), self.1)
|
||||
}
|
||||
|
||||
/// Get the secret key data from this [SecretHashDomain].
|
||||
pub fn into_secret(self) -> Secret<KEY_LEN> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
|
||||
hash::hash(v, dst).to(self.0.secret_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretHashDomainNamespace {
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`. Specifically,
|
||||
/// it evaluates [hash::hash] with the key of this HashDomainNamespace key as the key and `v`
|
||||
/// as the `data` and uses the result as the key for the new [HashDomain].
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix(&self, v: &[u8]) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v)
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v, self.1.clone())
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
/// by calling [SecretHashDomain::invoke_primitive] with the key of this
|
||||
/// [HashDomainNamespace] as `k` and `v` as `d`.
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret())
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret(), self.1.clone())
|
||||
}
|
||||
|
||||
// TODO: This entire API is not very nice; we need this for biscuits, but
|
||||
// it might be better to extract a special "biscuit"
|
||||
// labeled subkey and reinitialize the chain with this
|
||||
/// Get the secret key data from this [SecretHashDomain].
|
||||
pub fn danger_into_secret(self) -> Secret<KEY_LEN> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn keyed_hash(&self) -> &KeyedHash {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,46 @@
|
||||
use rosenpass_cipher_traits::primitives::Aead as AeadTrait;
|
||||
use static_assertions::const_assert;
|
||||
|
||||
pub mod subtle;
|
||||
|
||||
/// All keyed primitives in this crate use 32 byte keys
|
||||
pub const KEY_LEN: usize = 32;
|
||||
const_assert!(KEY_LEN == aead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == xaead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == Aead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == XAead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == hash_domain::KEY_LEN);
|
||||
|
||||
/// Authenticated encryption with associated data
|
||||
pub mod aead {
|
||||
pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
}
|
||||
/// Keyed hashing
|
||||
///
|
||||
/// This should only be used for implementation details; anything with relevance
|
||||
/// to the cryptographic protocol should use the facilities in [hash_domain], (though
|
||||
/// hash domain uses this module internally)
|
||||
pub use crate::subtle::keyed_hash::KeyedHash;
|
||||
|
||||
/// Authenticated encryption with associated data with a constant nonce
|
||||
pub mod xaead {
|
||||
pub use crate::subtle::xchacha20poly1305_ietf::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
}
|
||||
/// Authenticated encryption with associated data (AEAD)
|
||||
/// Chacha20poly1305 is used.
|
||||
#[cfg(feature = "experiment_libcrux_chachapoly")]
|
||||
pub use subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
|
||||
|
||||
/// Authenticated encryption with associated data (AEAD)
|
||||
/// Chacha20poly1305 is used.
|
||||
#[cfg(not(feature = "experiment_libcrux_chachapoly"))]
|
||||
pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
|
||||
|
||||
/// Authenticated encryption with associated data with a extended-length nonce (XAEAD)
|
||||
/// XChacha20poly1305 is used.
|
||||
pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305 as XAead;
|
||||
|
||||
/// Use Classic-McEcliece-460986 as the Static KEM.
|
||||
///
|
||||
/// See [rosenpass_oqs::ClassicMceliece460896] for more details.
|
||||
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
|
||||
|
||||
/// Use Kyber-512 as the Static KEM
|
||||
///
|
||||
/// See [rosenpass_oqs::Kyber512] for more details.
|
||||
#[cfg(not(feature = "experiment_libcrux_kyber"))]
|
||||
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
|
||||
#[cfg(feature = "experiment_libcrux_kyber")]
|
||||
pub use subtle::libcrux::kyber512::Kyber512 as EphemeralKem;
|
||||
|
||||
pub mod hash_domain;
|
||||
|
||||
pub mod kem {
|
||||
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
|
||||
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use blake2::digest::crypto_common::generic_array::GenericArray;
|
||||
use blake2::digest::crypto_common::typenum::U32;
|
||||
use blake2::digest::crypto_common::KeySizeUser;
|
||||
use blake2::digest::{FixedOutput, Mac, OutputSizeUser};
|
||||
use blake2::Blake2bMac;
|
||||
|
||||
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
type Impl = Blake2bMac<U32>;
|
||||
|
||||
type KeyLen = <Impl as KeySizeUser>::KeySize;
|
||||
type OutLen = <Impl as OutputSizeUser>::OutputSize;
|
||||
|
||||
const KEY_LEN: usize = typenum2const! { KeyLen };
|
||||
const OUT_LEN: usize = typenum2const! { OutLen };
|
||||
|
||||
pub const KEY_MIN: usize = KEY_LEN;
|
||||
pub const KEY_MAX: usize = KEY_LEN;
|
||||
pub const OUT_MIN: usize = OUT_LEN;
|
||||
pub const OUT_MAX: usize = OUT_LEN;
|
||||
|
||||
#[inline]
|
||||
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||
with_destination(|out: &mut [u8]| {
|
||||
let mut h = Impl::new_from_slice(key)?;
|
||||
h.update(data);
|
||||
|
||||
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy
|
||||
// but it introduces a ton of complexity. This cost me half an hour just to figure
|
||||
// out the right way to use the imports while allowing for zeroization.
|
||||
// An API based on slices might actually be simpler.
|
||||
let mut tmp = Zeroizing::new([0u8; OUT_LEN]);
|
||||
let mut tmp = GenericArray::from_mut_slice(tmp.as_mut());
|
||||
h.finalize_into(&mut tmp);
|
||||
copy_slice(tmp.as_ref()).to(out);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
|
||||
|
||||
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
|
||||
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
|
||||
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
|
||||
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(&nonce, ad, ct)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(&nonce, ad, plaintext, tag)?;
|
||||
Ok(())
|
||||
}
|
||||
79
ciphers/src/subtle/custom/incorrect_hmac_blake2b.rs
Normal file
79
ciphers/src/subtle/custom/incorrect_hmac_blake2b.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use rosenpass_cipher_traits::{
|
||||
algorithms::KeyedHashIncorrectHmacBlake2b,
|
||||
primitives::{InferKeyedHash, KeyedHash, KeyedHashTo},
|
||||
};
|
||||
use rosenpass_constant_time::xor;
|
||||
use rosenpass_to::{ops::copy_slice, To};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[cfg(not(feature = "experiment_libcrux_blake2"))]
|
||||
use crate::subtle::rust_crypto::blake2b::Blake2b;
|
||||
#[cfg(not(feature = "experiment_libcrux_blake2"))]
|
||||
use anyhow::Error;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_blake2")]
|
||||
use crate::subtle::libcrux::blake2b::{Blake2b, Error};
|
||||
|
||||
/// The key length, 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
|
||||
/// The hash length, 32 bytes or 256 bits.
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||
///
|
||||
/// It accepts 32 byte keys, exclusively.
|
||||
///
|
||||
/// This will be replaced, likely by Kekkac at some point soon.
|
||||
/// <https://github.com/rosenpass/rosenpass/pull/145>
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::custom::incorrect_hmac_blake2b::IncorrectHmacBlake2bCore;
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashTo;
|
||||
/// use rosenpass_to::To;
|
||||
/// let key: [u8; 32] = [0; 32];
|
||||
/// let data: [u8; 32] = [255; 32];
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; 32];
|
||||
///
|
||||
/// assert!(IncorrectHmacBlake2bCore::keyed_hash_to(&key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[5, 152, 135, 141, 151, 106, 147, 8, 220, 95, 38, 66, 29, 33, 3,
|
||||
/// 104, 250, 114, 131, 119, 27, 56, 59, 44, 11, 67, 230, 113, 112, 20, 80, 103];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
///```
|
||||
///
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct IncorrectHmacBlake2bCore;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for IncorrectHmacBlake2bCore {
|
||||
type Error = Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
|
||||
type Key = Zeroizing<[u8; KEY_LEN]>;
|
||||
let mut tmp_key = Key::default();
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&IPAD).to(tmp_key.as_mut());
|
||||
let mut outer_data = Key::default();
|
||||
Blake2b::keyed_hash_to(&tmp_key, data).to(&mut outer_data)?;
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&OPAD).to(tmp_key.as_mut());
|
||||
Blake2b::keyed_hash_to(&tmp_key, outer_data.as_ref()).to(out)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>;
|
||||
|
||||
impl KeyedHashIncorrectHmacBlake2b for IncorrectHmacBlake2bCore {}
|
||||
3
ciphers/src/subtle/custom/mod.rs
Normal file
3
ciphers/src/subtle/custom/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Own implementations of custom algorithms
|
||||
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
@@ -1,46 +0,0 @@
|
||||
use anyhow::ensure;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use rosenpass_constant_time::xor;
|
||||
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||
|
||||
use crate::subtle::blake2b;
|
||||
|
||||
pub const KEY_LEN: usize = 32;
|
||||
pub const KEY_MIN: usize = KEY_LEN;
|
||||
pub const KEY_MAX: usize = KEY_LEN;
|
||||
pub const OUT_MIN: usize = blake2b::OUT_MIN;
|
||||
pub const OUT_MAX: usize = blake2b::OUT_MAX;
|
||||
|
||||
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||
///
|
||||
/// It accepts 32 byte keys, exclusively.
|
||||
///
|
||||
/// This will be replaced, likely by Kekkac at some point soon.
|
||||
/// <https://github.com/rosenpass/rosenpass/pull/145>
|
||||
#[inline]
|
||||
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
|
||||
with_destination(|out: &mut [u8]| {
|
||||
// Not bothering with padding; the implementation
|
||||
// uses appropriately sized keys.
|
||||
ensure!(key.len() == KEY_LEN);
|
||||
|
||||
type Key = Zeroizing<[u8; KEY_LEN]>;
|
||||
let mut tmp_key = Key::default();
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&IPAD).to(tmp_key.as_mut());
|
||||
let mut outer_data = Key::default();
|
||||
blake2b::hash(tmp_key.as_ref(), data).to(outer_data.as_mut())?;
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&OPAD).to(tmp_key.as_mut());
|
||||
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
65
ciphers/src/subtle/keyed_hash.rs
Normal file
65
ciphers/src/subtle/keyed_hash.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! This module provides types that enabling choosing the keyed hash building block to be used at
|
||||
//! runtime (using enums) instead of at compile time (using generics).
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::subtle::{
|
||||
custom::incorrect_hmac_blake2b::IncorrectHmacBlake2b, rust_crypto::keyed_shake256::SHAKE256_32,
|
||||
};
|
||||
|
||||
/// Length of symmetric key throughout Rosenpass.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
|
||||
/// The hash is used as a symmetric key and should have the same length.
|
||||
pub const HASH_LEN: usize = KEY_LEN;
|
||||
|
||||
/// Provides a way to pick which keyed hash to use at runtime.
|
||||
/// Implements [`KeyedHashInstance`] to allow hashing using the respective algorithm.
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum KeyedHash {
|
||||
/// A hasher backed by [`SHAKE256_32`].
|
||||
KeyedShake256(SHAKE256_32),
|
||||
/// A hasher backed by [`IncorrectHmacBlake2b`].
|
||||
IncorrectHmacBlake2b(IncorrectHmacBlake2b),
|
||||
}
|
||||
|
||||
impl KeyedHash {
|
||||
/// Creates an [`KeyedHash`] backed by SHAKE256.
|
||||
pub fn keyed_shake256() -> Self {
|
||||
Self::KeyedShake256(Default::default())
|
||||
}
|
||||
|
||||
/// Creates an [`KeyedHash`] backed by Blake2B.
|
||||
pub fn incorrect_hmac_blake2b() -> Self {
|
||||
Self::IncorrectHmacBlake2b(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyedHashInstance<KEY_LEN, HASH_LEN> for KeyedHash {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
Self::KeyedShake256(h) => h.keyed_hash(key, data, out)?,
|
||||
Self::IncorrectHmacBlake2b(h) => h.keyed_hash(key, data, out)?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for KeyedHash {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::KeyedShake256(_) => write!(f, "KeyedShake256_32"),
|
||||
Self::IncorrectHmacBlake2b(_) => write!(f, "IncorrectHmacBlake2b"),
|
||||
}
|
||||
}
|
||||
}
|
||||
88
ciphers/src/subtle/libcrux/blake2b.rs
Normal file
88
ciphers/src/subtle/libcrux/blake2b.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
//! Implementation of the [`KeyedHashBlake2b`] trait based on the [`libcrux_blake2`] crate.
|
||||
|
||||
use libcrux_blake2::Blake2bBuilder;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::KeyedHashBlake2b;
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::HASH_LEN;
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::KEY_LEN;
|
||||
|
||||
/// Describles which error occurred
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// An unexpected internal error occurred. Should never be returned and points to a bug in the
|
||||
/// implementation.
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Indicates that the provided data was too long.
|
||||
#[error("data is too long")]
|
||||
DataTooLong,
|
||||
}
|
||||
|
||||
/// Hasher for the given `data` with the Blake2b hash function.
|
||||
pub struct Blake2b;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
|
||||
type Error = Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut h = Blake2bBuilder::new_keyed_const(key)
|
||||
// this may fail if the key length is invalid, but 32 is fine
|
||||
.map_err(|_| Error::InternalError)?
|
||||
.build_const_digest_len()
|
||||
.map_err(|_|
|
||||
// this can only fail if the output length is invalid, but 32 is fine.
|
||||
Error::InternalError)?;
|
||||
|
||||
h.update(data).map_err(|_| Error::DataTooLong)?;
|
||||
h.finalize(out);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyedHashBlake2b for Blake2b {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
use rand::RngCore;
|
||||
|
||||
#[test]
|
||||
fn fuzz_equivalence_libcrux_old_new() {
|
||||
let datas: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut hash_left = [0; 32];
|
||||
let mut hash_right = [0; 32];
|
||||
|
||||
for data in datas {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
|
||||
crate::subtle::rust_crypto::blake2b::Blake2b::keyed_hash(
|
||||
&key,
|
||||
data,
|
||||
&mut hash_left,
|
||||
)
|
||||
.unwrap();
|
||||
crate::subtle::libcrux::blake2b::Blake2b::keyed_hash(&key, data, &mut hash_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(hash_left, hash_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
274
ciphers/src/subtle/libcrux/chacha20poly1305_ietf.rs
Normal file
274
ciphers/src/subtle/libcrux/chacha20poly1305_ietf.rs
Normal file
@@ -0,0 +1,274 @@
|
||||
//! Implementation of the [`AeadChaCha20Poly1305`] trait based on the [`libcrux_chacha20poly1305`] crate.
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
|
||||
/// An implementation of the ChaCha20Poly1305 AEAD based on libcrux
|
||||
pub struct ChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
let (ctxt, tag) = libcrux_chacha20poly1305::encrypt(key, plaintext, ciphertext, ad, nonce)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
// return an error of the destination buffer is longer than expected
|
||||
// because the caller wouldn't know where the end is
|
||||
if ctxt.len() + tag.len() != ciphertext.len() {
|
||||
return Err(AeadError::InternalError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
let ptxt = libcrux_chacha20poly1305::decrypt(key, plaintext, ciphertext, ad, nonce)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
|
||||
// return an error of the destination buffer is longer than expected
|
||||
// because the caller wouldn't know where the end is
|
||||
if ptxt.len() != plaintext.len() {
|
||||
return Err(AeadError::DecryptError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}
|
||||
|
||||
/// The idea of these tests is to check that the above implemenatation behaves, by and large, the
|
||||
/// same as the one from the old libcrux and the one from RustCrypto. You can consider them janky,
|
||||
/// self-rolled property-based tests.
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
use rand::RngCore;
|
||||
|
||||
#[test]
|
||||
fn proptest_equivalence_libcrux_rustcrypto() {
|
||||
use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as RustCryptoChaCha20Poly1305;
|
||||
let ptxts: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut ctxt_left = [0; 64 + TAG_LEN];
|
||||
let mut ctxt_right = [0; 64 + TAG_LEN];
|
||||
|
||||
let mut ptxt_left = [0; 64];
|
||||
let mut ptxt_right = [0; 64];
|
||||
|
||||
let nonce = [0; NONCE_LEN];
|
||||
let ad = b"";
|
||||
|
||||
for ptxt in ptxts {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
|
||||
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
|
||||
|
||||
let ptxt_left = &mut ptxt_left[..ptxt.len()];
|
||||
let ptxt_right = &mut ptxt_right[..ptxt.len()];
|
||||
|
||||
RustCryptoChaCha20Poly1305
|
||||
.encrypt(ctxt_left, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
ChaCha20Poly1305
|
||||
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ctxt_left, ctxt_right);
|
||||
|
||||
RustCryptoChaCha20Poly1305
|
||||
.decrypt(ptxt_left, &key, &nonce, ad, ctxt_left)
|
||||
.unwrap();
|
||||
ChaCha20Poly1305
|
||||
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ptxt_left, ptxt);
|
||||
assert_eq!(ptxt_right, ptxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "experiment_libcrux_chachapoly_test")]
|
||||
fn proptest_equivalence_libcrux_old_new() {
|
||||
let ptxts: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut ctxt_left = [0; 64 + TAG_LEN];
|
||||
let mut ctxt_right = [0; 64 + TAG_LEN];
|
||||
|
||||
let mut ptxt_left = [0; 64];
|
||||
let mut ptxt_right = [0; 64];
|
||||
|
||||
let nonce = [0; NONCE_LEN];
|
||||
let ad = b"";
|
||||
|
||||
for ptxt in ptxts {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
|
||||
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
|
||||
|
||||
let ptxt_left = &mut ptxt_left[..ptxt.len()];
|
||||
let ptxt_right = &mut ptxt_right[..ptxt.len()];
|
||||
|
||||
encrypt(ctxt_left, &key, &nonce, ad, ptxt).unwrap();
|
||||
ChaCha20Poly1305
|
||||
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ctxt_left, ctxt_right);
|
||||
|
||||
decrypt(ptxt_left, &key, &nonce, ad, ctxt_left).unwrap();
|
||||
ChaCha20Poly1305
|
||||
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ptxt_left, ptxt);
|
||||
assert_eq!(ptxt_right, ptxt);
|
||||
}
|
||||
}
|
||||
|
||||
// The old libcrux functions:
|
||||
|
||||
// The functions below are from the old libcrux backend. I am keeping them around so we can
|
||||
// check if they behave the same.
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// Encrypts using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
/// Key and nonce MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
|
||||
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
|
||||
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
|
||||
/// `plaintext.len()` + [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
///
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8; PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
|
||||
/// assert!(res.is_ok());
|
||||
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// # 8, 114, 85, 4, 25];
|
||||
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
|
||||
copy_slice(plaintext).to(ciphertext);
|
||||
let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap();
|
||||
copy_slice(crux_tag.as_ref()).to(mac);
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
/// `ad`. using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
///
|
||||
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
|
||||
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
|
||||
/// assert!(res.is_ok());
|
||||
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(expected_plaintext, plaintext_buffer);
|
||||
///
|
||||
///```
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
let crux_tag = C::Tag::from_slice(mac).unwrap();
|
||||
|
||||
copy_slice(ciphertext).to(plaintext);
|
||||
libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap();
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
133
ciphers/src/subtle/libcrux/kyber512.rs
Normal file
133
ciphers/src/subtle/libcrux/kyber512.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
//! Implementation of the [`KemKyber512`] trait based on the [`libcrux_ml_kem`] crate.
|
||||
|
||||
use libcrux_ml_kem::kyber512;
|
||||
use rand::RngCore;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::KemKyber512;
|
||||
use rosenpass_cipher_traits::primitives::{Kem, KemError};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::kem_kyber512::{CT_LEN, PK_LEN, SHK_LEN, SK_LEN};
|
||||
|
||||
/// An implementation of the Kyber512 KEM based on libcrux
|
||||
pub struct Kyber512;
|
||||
|
||||
impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for Kyber512 {
|
||||
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
|
||||
let mut randomness = [0u8; libcrux_ml_kem::KEY_GENERATION_SEED_SIZE];
|
||||
rand::thread_rng().fill_bytes(&mut randomness);
|
||||
|
||||
let key_pair = kyber512::generate_key_pair(randomness);
|
||||
|
||||
let new_sk: &[u8; SK_LEN] = key_pair.sk();
|
||||
let new_pk: &[u8; PK_LEN] = key_pair.pk();
|
||||
|
||||
sk.clone_from_slice(new_sk);
|
||||
pk.clone_from_slice(new_pk);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
ct: &mut [u8; CT_LEN],
|
||||
pk: &[u8; PK_LEN],
|
||||
) -> Result<(), KemError> {
|
||||
let mut randomness = [0u8; libcrux_ml_kem::SHARED_SECRET_SIZE];
|
||||
rand::thread_rng().fill_bytes(&mut randomness);
|
||||
|
||||
let (new_ct, new_shk) = kyber512::encapsulate(&pk.into(), randomness);
|
||||
let new_ct: &[u8; CT_LEN] = new_ct.as_slice();
|
||||
|
||||
shk.clone_from_slice(&new_shk);
|
||||
ct.clone_from_slice(new_ct);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
sk: &[u8; SK_LEN],
|
||||
ct: &[u8; CT_LEN],
|
||||
) -> Result<(), KemError> {
|
||||
let new_shk: [u8; SHK_LEN] = kyber512::decapsulate(&sk.into(), &ct.into());
|
||||
shk.clone_from(&new_shk);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Kyber512 {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl KemKyber512 for Kyber512 {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
|
||||
// Test that libcrux and OQS produce the same results
|
||||
#[test]
|
||||
fn proptest_equivalence_libcrux_oqs() {
|
||||
use rosenpass_oqs::Kyber512 as OqsKyber512;
|
||||
|
||||
let (mut sk1, mut pk1) = ([0; SK_LEN], [0; PK_LEN]);
|
||||
let (mut sk2, mut pk2) = ([0; SK_LEN], [0; PK_LEN]);
|
||||
|
||||
let mut ct_left = [0; CT_LEN];
|
||||
let mut ct_right = [0; CT_LEN];
|
||||
|
||||
let mut shk_enc_left = [0; SHK_LEN];
|
||||
let mut shk_enc_right = [0; SHK_LEN];
|
||||
|
||||
// naming schema: shk_dec_{encapsing lib}_{decapsing lib}
|
||||
// should be the same if the encapsing lib was the same.
|
||||
let mut shk_dec_left_left = [0; SHK_LEN];
|
||||
let mut shk_dec_left_right = [0; SHK_LEN];
|
||||
let mut shk_dec_right_left = [0; SHK_LEN];
|
||||
let mut shk_dec_right_right = [0; SHK_LEN];
|
||||
|
||||
for _ in 0..1000 {
|
||||
let sk1 = &mut sk1;
|
||||
let pk1 = &mut pk1;
|
||||
let sk2 = &mut sk2;
|
||||
let pk2 = &mut pk2;
|
||||
|
||||
let ct_left = &mut ct_left;
|
||||
let ct_right = &mut ct_right;
|
||||
|
||||
let shk_enc_left = &mut shk_enc_left;
|
||||
let shk_enc_right = &mut shk_enc_right;
|
||||
|
||||
let shk_dec_left_left = &mut shk_dec_left_left;
|
||||
let shk_dec_left_right = &mut shk_dec_left_right;
|
||||
let shk_dec_right_left = &mut shk_dec_right_left;
|
||||
let shk_dec_right_right = &mut shk_dec_right_right;
|
||||
|
||||
Kyber512.keygen(sk1, pk1).unwrap();
|
||||
Kyber512.keygen(sk2, pk2).unwrap();
|
||||
|
||||
Kyber512.encaps(shk_enc_left, ct_left, pk2).unwrap();
|
||||
OqsKyber512.encaps(shk_enc_right, ct_right, pk2).unwrap();
|
||||
|
||||
Kyber512.decaps(shk_dec_left_left, sk2, ct_left).unwrap();
|
||||
Kyber512.decaps(shk_dec_right_left, sk2, ct_right).unwrap();
|
||||
|
||||
OqsKyber512
|
||||
.decaps(shk_dec_left_right, sk2, ct_left)
|
||||
.unwrap();
|
||||
OqsKyber512
|
||||
.decaps(shk_dec_right_right, sk2, ct_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(shk_enc_left, shk_dec_left_left);
|
||||
assert_eq!(shk_enc_left, shk_dec_left_right);
|
||||
|
||||
assert_eq!(shk_enc_right, shk_dec_right_left);
|
||||
assert_eq!(shk_enc_right, shk_dec_right_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
ciphers/src/subtle/libcrux/mod.rs
Normal file
14
ciphers/src/subtle/libcrux/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
//! Implementations backed by libcrux, a verified crypto library.
|
||||
//!
|
||||
//! [Website](https://cryspen.com/libcrux/)
|
||||
//!
|
||||
//! [Github](https://github.com/cryspen/libcrux)
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_blake2")]
|
||||
pub mod blake2b;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_chachapoly")]
|
||||
pub mod chacha20poly1305_ietf;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_kyber")]
|
||||
pub mod kyber512;
|
||||
@@ -1,4 +1,16 @@
|
||||
pub mod blake2b;
|
||||
pub mod chacha20poly1305_ietf;
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
//! Contains the implementations of the crypto algorithms used throughout Rosenpass.
|
||||
|
||||
pub mod keyed_hash;
|
||||
|
||||
pub use custom::incorrect_hmac_blake2b;
|
||||
pub use rust_crypto::{blake2b, keyed_shake256};
|
||||
|
||||
pub mod custom;
|
||||
pub mod rust_crypto;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "experiment_libcrux_define_blake2",
|
||||
feature = "experiment_libcrux_define_chachapoly",
|
||||
feature = "experiment_libcrux_define_kyber",
|
||||
))]
|
||||
pub mod libcrux;
|
||||
|
||||
44
ciphers/src/subtle/rust_crypto/blake2b.rs
Normal file
44
ciphers/src/subtle/rust_crypto/blake2b.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use blake2::digest::crypto_common::generic_array::GenericArray;
|
||||
use blake2::digest::crypto_common::typenum::U32;
|
||||
use blake2::digest::{FixedOutput, Mac};
|
||||
use blake2::Blake2bMac;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
use rosenpass_to::{ops::copy_slice, To};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::{HASH_LEN, KEY_LEN};
|
||||
|
||||
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
|
||||
/// with output and key length of 32 bytes (see [Blake2bMac]).
|
||||
type Impl = Blake2bMac<U32>;
|
||||
|
||||
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
|
||||
/// The both the length of the output the length of the key 32 bytes (or 256 bits).
|
||||
pub struct Blake2b;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut h = Impl::new_from_slice(key)?;
|
||||
h.update(data);
|
||||
|
||||
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy,
|
||||
// but it introduces a ton of complexity. This cost me half an hour just to figure
|
||||
// out the right way to use the imports while allowing for zeroization.
|
||||
// An API based on slices might actually be simpler.
|
||||
let mut tmp = Zeroizing::new([0u8; HASH_LEN]);
|
||||
let tmp = GenericArray::from_mut_slice(tmp.as_mut());
|
||||
h.finalize_into(tmp);
|
||||
copy_slice(tmp.as_ref()).to(out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl rosenpass_cipher_traits::algorithms::KeyedHashBlake2b for Blake2b {}
|
||||
79
ciphers/src/subtle/rust_crypto/chacha20poly1305_ietf.rs
Normal file
79
ciphers/src/subtle/rust_crypto/chacha20poly1305_ietf.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadInPlace, KeyInit};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
|
||||
/// Implements the [`Aead`] and [`AeadChaCha20Poly1305`] traits backed by the RustCrypto
|
||||
/// implementation.
|
||||
pub struct ChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
let mac_value = encrypter
|
||||
.encrypt_in_place_detached(nonce, ad, ct)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
decrypter
|
||||
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}
|
||||
117
ciphers/src/subtle/rust_crypto/keyed_shake256.rs
Normal file
117
ciphers/src/subtle/rust_crypto/keyed_shake256.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use anyhow::ensure;
|
||||
use rosenpass_cipher_traits::primitives::{InferKeyedHash, KeyedHash};
|
||||
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||
use sha3::Shake256;
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_shake256::{HASH_LEN, KEY_LEN};
|
||||
|
||||
/// An implementation of the [`KeyedHash`] trait backed by the RustCrypto implementation of SHAKE256.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>;
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN>
|
||||
for SHAKE256Core<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = anyhow::Error;
|
||||
|
||||
/// Provides a keyed hash function based on SHAKE256. To work for the protocol, the output length
|
||||
/// and key length are fixed to 32 bytes (also see [KEY_LEN] and [HASH_LEN]).
|
||||
///
|
||||
/// Note that the SHAKE256 is designed for 64 bytes output length, which we truncate to 32 bytes
|
||||
/// to work well with the overall protocol. Referring to Table 4 of FIPS 202, this offers the
|
||||
/// same collision resistance as SHAKE128, but 256 bits of preimage resistance. We therefore
|
||||
/// prefer a truncated SHAKE256 over SHAKE128.
|
||||
///
|
||||
/// #Examples
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core;
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; 32] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
///
|
||||
/// assert!(SHAKE256Core::<32, 32>::keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11,
|
||||
/// 187, 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
// Since SHAKE256 is a XOF, we fix the output length manually to what is required for the
|
||||
// protocol.
|
||||
ensure!(out.len() == HASH_LEN);
|
||||
// Not bothering with padding; the implementation
|
||||
// uses appropriately sized keys.
|
||||
ensure!(key.len() == KEY_LEN);
|
||||
let mut shake256 = Shake256::default();
|
||||
shake256.update(key);
|
||||
shake256.update(data);
|
||||
|
||||
// Since we use domain separation extensively, related outputs of the truncated XOF
|
||||
// are not a concern. This follows the NIST recommendations in Section A.2 of the FIPS 202
|
||||
// standard, (pages 24/25, i.e., 32/33 in the PDF).
|
||||
shake256.finalize_xof().read(out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> Default for SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// This type provides the same functionality as [SHAKE256Core], but bound to an instance.
|
||||
/// In contrast to [SHAKE256Core], this allows for type interference and thus allows the user of the
|
||||
/// type to omit explicit type parameters when instantiating the type or using it.
|
||||
///
|
||||
/// The instantiation is based on the [InferKeyedHash] trait.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::{SHAKE256};
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; KEY_LEN] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
/// assert!(SHAKE256::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
|
||||
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
pub type SHAKE256<const KEY_LEN: usize, const HASH_LEN: usize> =
|
||||
InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>;
|
||||
|
||||
/// The SHAKE256_32 type is a specific instance of the [SHAKE256] type with the key length and hash
|
||||
/// length fixed to 32 bytes.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::keyed_shake256::{SHAKE256_32};
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; 32] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
///
|
||||
/// assert!(SHAKE256_32::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
|
||||
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
pub type SHAKE256_32 = SHAKE256<32, 32>;
|
||||
7
ciphers/src/subtle/rust_crypto/mod.rs
Normal file
7
ciphers/src/subtle/rust_crypto/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Implementations backed by RustCrypto
|
||||
|
||||
pub mod blake2b;
|
||||
pub mod keyed_shake256;
|
||||
|
||||
pub mod chacha20poly1305_ietf;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
164
ciphers/src/subtle/rust_crypto/xchacha20poly1305_ietf.rs
Normal file
164
ciphers/src/subtle/rust_crypto/xchacha20poly1305_ietf.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::AeadXChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError, AeadWithNonceInCiphertext};
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::XChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadInPlace, KeyInit};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::{
|
||||
KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
/// Implements the [`Aead`] and [`AeadXChaCha20Poly1305`] traits backed by the RustCrypto
|
||||
/// implementation.
|
||||
pub struct XChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for XChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
let mac_value = encrypter
|
||||
.encrypt_in_place_detached(nonce, ad, ct)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
decrypter
|
||||
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
|
||||
|
||||
/// Encrypts using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
|
||||
/// `key` and `nonce` MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
|
||||
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN].
|
||||
/// In contrast to [chacha20poly1305_ietf::encrypt](crate::subtle::chacha20poly1305_ietf::encrypt) and
|
||||
/// [chacha20poly1305_ietf_libcrux::encrypt](crate::subtle::chacha20poly1305_ietf_libcrux::encrypt),
|
||||
/// `nonce` is also written into `ciphertext` and therefore ciphertext MUST have a length
|
||||
/// of at least [NONCE_LEN] + `plaintext.len()` + [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8; NONCE_LEN + PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
///
|
||||
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
|
||||
/// # assert!(res.is_ok());
|
||||
/// # let expected_ciphertext: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/// # 0, 0, 0, 0, 8, 241, 229, 253, 200, 81, 248, 30, 183, 149, 134, 168, 149, 87, 109, 49, 159, 108,
|
||||
/// # 206, 89, 51, 232, 232, 197, 163, 253, 254, 208, 73, 76, 253, 13, 247, 162, 133, 184, 177, 44,
|
||||
/// # 73, 138, 176, 193, 61, 248, 61, 183, 164, 192, 214, 168, 4, 1, 62, 243, 36, 48, 149, 164, 6];
|
||||
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
|
||||
///```
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
XChaCha20Poly1305
|
||||
.encrypt_with_nonce_in_ctxt(ciphertext, key, nonce, ad, plaintext)
|
||||
.map_err(anyhow::Error::from)
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
/// `ad`. using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
|
||||
///
|
||||
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
|
||||
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN] - [NONCE_LEN].
|
||||
///
|
||||
/// In contrast to [chacha20poly1305_ietf::decrypt](crate::subtle::chacha20poly1305_ietf::decrypt) and
|
||||
/// [chacha20poly1305_ietf_libcrux::decrypt](crate::subtle::chacha20poly1305_ietf_libcrux::decrypt),
|
||||
/// `ciperhtext` MUST include the as it is not given otherwise.
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/// # 0, 0, 0, 0, 8, 241, 229, 253, 200, 81, 248, 30, 183, 149, 134, 168, 149, 87, 109, 49, 159, 108,
|
||||
/// # 206, 89, 51, 232, 232, 197, 163, 253, 254, 208, 73, 76, 253, 13, 247, 162, 133, 184, 177, 44,
|
||||
/// # 73, 138, 176, 193, 61, 248, 61, 183, 164, 192, 214, 168, 4, 1, 62, 243, 36, 48, 149, 164, 6];
|
||||
/// // this is the ciphertext generated by the example for the encryption
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN + NONCE_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, additional_data, ciphertext);
|
||||
/// assert!(res.is_ok());
|
||||
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(expected_plaintext, plaintext_buffer);
|
||||
///
|
||||
///```
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
XChaCha20Poly1305
|
||||
.decrypt_with_nonce_in_ctxt(plaintext, key, ad, ciphertext)
|
||||
.map_err(anyhow::Error::from)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::XChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
|
||||
|
||||
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
|
||||
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
|
||||
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
|
||||
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (n, ct_mac) = ciphertext.split_at_mut(NONCE_LEN);
|
||||
let (ct, mac) = ct_mac.split_at_mut(ct_mac.len() - TAG_LEN);
|
||||
copy_slice(nonce).to(n);
|
||||
copy_slice(plaintext).to(ct);
|
||||
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(&nonce, ad, ct)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (n, ct_mac) = ciphertext.split_at(NONCE_LEN);
|
||||
let (ct, mac) = ct_mac.split_at(ct_mac.len() - TAG_LEN);
|
||||
let nonce = GenericArray::from_slice(n);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(&nonce, ad, plaintext, tag)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -8,9 +8,19 @@ description = "Rosenpass internal utilities for constant time crypto implementat
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
constant_time_tests = []
|
||||
|
||||
[dependencies]
|
||||
rosenpass-to = { workspace = true }
|
||||
memsec = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||
|
||||
114
constant-time/src/compare.rs
Normal file
114
constant-time/src/compare.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
//! Constant-time comparison
|
||||
|
||||
use core::ptr;
|
||||
|
||||
/// Little endian memcmp version of [quinier/memsec](https://github.com/quininer/memsec/blob/bbc647967ff6d20d6dccf1c85f5d9037fcadd3b0/src/lib.rs#L30)
|
||||
///
|
||||
/// # Panic & Safety
|
||||
///
|
||||
/// Both input arrays must be at least of the indicated length.
|
||||
///
|
||||
/// See [std::ptr::read_volatile] on safety.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// let a = [1, 2, 3, 4];
|
||||
/// let b = [1, 2, 3, 4];
|
||||
/// let c = [1, 2, 2, 5];
|
||||
/// let d = [1, 2, 2, 4];
|
||||
///
|
||||
/// unsafe {
|
||||
/// use rosenpass_constant_time::memcmp_le;
|
||||
/// assert_eq!(memcmp_le(a.as_ptr(), b.as_ptr(), 4), 0);
|
||||
/// assert!(memcmp_le(a.as_ptr(), c.as_ptr(), 4) < 0);
|
||||
/// assert!(memcmp_le(a.as_ptr(), d.as_ptr(), 4) > 0);
|
||||
/// assert_eq!(memcmp_le(a.as_ptr(), b.as_ptr(), 2), 0);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(never)]
|
||||
pub unsafe fn memcmp_le(b1: *const u8, b2: *const u8, len: usize) -> i32 {
|
||||
let mut res = 0;
|
||||
for i in 0..len {
|
||||
let diff =
|
||||
i32::from(ptr::read_volatile(b1.add(i))) - i32::from(ptr::read_volatile(b2.add(i)));
|
||||
res = (res & (((diff - 1) & !diff) >> 8)) | diff;
|
||||
}
|
||||
((res - 1) >> 8) + (res >> 8) + 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn memcmp_le_test() {
|
||||
// use rosenpass_constant_time::memcmp_le;
|
||||
let a = [0, 1, 0, 0];
|
||||
let b = [0, 0, 0, 1];
|
||||
assert_eq!(-1, unsafe { memcmp_le(a.as_ptr(), b.as_ptr(), 4) });
|
||||
assert_eq!(0, unsafe { memcmp_le(a.as_ptr(), a.as_ptr(), 4) });
|
||||
assert_eq!(1, unsafe { memcmp_le(b.as_ptr(), a.as_ptr(), 4) });
|
||||
}
|
||||
|
||||
/// compares two slices of memory content and returns an integer indicating the relationship between
|
||||
/// the slices
|
||||
///
|
||||
/// ## Returns
|
||||
/// - <0 if the first byte that does not match both slices has a lower value in `a` than in `b`
|
||||
/// - 0 if the contents are equal
|
||||
/// - >0 if the first byte that does not match both slices has a higher value in `a` than in `b`
|
||||
///
|
||||
/// ## Leaks
|
||||
/// If the two slices have differents lengths, the function will return immediately. This
|
||||
/// effectively leaks the information whether the slices have equal length or not. This is widely
|
||||
/// considered safe.
|
||||
///
|
||||
/// The execution time of the function grows approx. linear with the length of the input. This is
|
||||
/// considered safe.
|
||||
///
|
||||
/// ## Tests
|
||||
/// For discussion on how to ensure the constant-time execution of this function, see
|
||||
/// <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass_constant_time::compare;
|
||||
/// let a = [0, 1, 0, 0];
|
||||
/// let b = [0, 0, 0, 1];
|
||||
/// assert_eq!(-1, compare(&a, &b));
|
||||
/// assert_eq!(0, compare(&a, &a));
|
||||
/// assert_eq!(1, compare(&b, &a));
|
||||
/// ```
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This function will panic if the input arrays are of different lengths.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// use rosenpass_constant_time::compare;
|
||||
/// let a = [0, 1, 0];
|
||||
/// let b = [0, 0, 0, 1];
|
||||
/// compare(&a, &b);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn compare(a: &[u8], b: &[u8]) -> i32 {
|
||||
assert!(a.len() == b.len());
|
||||
unsafe { memcmp_le(a.as_ptr(), b.as_ptr(), a.len()) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::compare::memcmp_le;
|
||||
|
||||
#[test]
|
||||
fn memcmp_le_test() {
|
||||
let a = [1, 2, 3, 4];
|
||||
let b = [1, 2, 3, 4];
|
||||
let c = [1, 2, 2, 5];
|
||||
let d = [1, 2, 2, 4];
|
||||
|
||||
unsafe {
|
||||
assert_eq!(memcmp_le(a.as_ptr(), b.as_ptr(), 4), 0);
|
||||
assert!(memcmp_le(a.as_ptr(), c.as_ptr(), 4) < 0);
|
||||
assert!(memcmp_le(a.as_ptr(), d.as_ptr(), 4) > 0);
|
||||
assert_eq!(memcmp_le(a.as_ptr(), b.as_ptr(), 2), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
constant-time/src/increment.rs
Normal file
58
constant-time/src/increment.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! Incrementing numbers
|
||||
|
||||
use core::hint::black_box;
|
||||
|
||||
/// Interpret the given slice as a little-endian unsigned integer
|
||||
/// and increment that integer.
|
||||
///
|
||||
/// # Leaks
|
||||
/// This function may leak timing information in the following ways:
|
||||
///
|
||||
/// - The function execution time is linearly proportional to the input length
|
||||
/// - The number of carry operations that occur may affect timing slightly
|
||||
/// - Memory access patterns are sequential and predictable
|
||||
///
|
||||
/// The carry operation timing variation is mitigated through the use of black_box,
|
||||
/// but the linear scaling with input size is inherent to the operation.
|
||||
/// These timing characteristics are generally considered acceptable for most
|
||||
/// cryptographic counter implementations.
|
||||
///
|
||||
/// ## Tests
|
||||
/// For discussion on how to ensure the constant-time execution of this function, see
|
||||
/// <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass_constant_time::increment as inc;
|
||||
/// use rosenpass_to::To;
|
||||
///
|
||||
/// fn testcase(v: &[u8], correct: &[u8]) {
|
||||
/// let mut v = v.to_owned();
|
||||
/// inc(&mut v);
|
||||
/// assert_eq!(&v, correct);
|
||||
/// }
|
||||
///
|
||||
/// testcase(b"", b"");
|
||||
/// testcase(b"\x00", b"\x01");
|
||||
/// testcase(b"\x01", b"\x02");
|
||||
/// testcase(b"\xfe", b"\xff");
|
||||
/// testcase(b"\xff", b"\x00");
|
||||
/// testcase(b"\x00\x00", b"\x01\x00");
|
||||
/// testcase(b"\x01\x00", b"\x02\x00");
|
||||
/// testcase(b"\xfe\x00", b"\xff\x00");
|
||||
/// testcase(b"\xff\x00", b"\x00\x01");
|
||||
/// testcase(b"\x00\x00\x00\x00\x00\x00", b"\x01\x00\x00\x00\x00\x00");
|
||||
/// testcase(b"\x00\xa3\x00\x77\x00\x00", b"\x01\xa3\x00\x77\x00\x00");
|
||||
/// testcase(b"\xff\xa3\x00\x77\x00\x00", b"\x00\xa4\x00\x77\x00\x00");
|
||||
/// testcase(b"\xff\xff\xff\x77\x00\x00", b"\x00\x00\x00\x78\x00\x00");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn increment(v: &mut [u8]) {
|
||||
let mut carry = 1u8;
|
||||
for val in v.iter_mut() {
|
||||
let (v, c) = black_box(*val).overflowing_add(black_box(carry));
|
||||
*black_box(val) = v;
|
||||
*black_box(&mut carry) = black_box(black_box(c) as u8);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +1,46 @@
|
||||
use core::hint::black_box;
|
||||
#![warn(missing_docs)]
|
||||
#![warn(clippy::missing_docs_in_private_items)]
|
||||
//! constant-time implementations of some primitives
|
||||
//!
|
||||
//! Rosenpass internal library providing basic constant-time operations.
|
||||
//!
|
||||
//! ## TODO
|
||||
//! Figure out methodology to ensure that code is actually constant time, see
|
||||
//! <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rosenpass_constant_time::{memcmp, compare};
|
||||
//!
|
||||
//! let a = [1, 2, 3, 4];
|
||||
//! let b = [1, 2, 3, 4];
|
||||
//! let c = [1, 2, 3, 5];
|
||||
//!
|
||||
//! // Compare for equality
|
||||
//! assert!(memcmp(&a, &b));
|
||||
//! assert!(!memcmp(&a, &c));
|
||||
//!
|
||||
//! // Compare lexicographically
|
||||
//! assert_eq!(compare(&a, &c), -1); // a < c
|
||||
//! assert_eq!(compare(&c, &a), 1); // c > a
|
||||
//! assert_eq!(compare(&a, &b), 0); // a == b
|
||||
//! ```
|
||||
//!
|
||||
//! # Security Notes
|
||||
//!
|
||||
//! While these functions aim to be constant-time, they may leak timing information in some cases:
|
||||
//!
|
||||
//! - Length mismatches between inputs are immediately detectable
|
||||
//! - Execution time scales linearly with input size
|
||||
|
||||
use rosenpass_to::{with_destination, To};
|
||||
mod compare;
|
||||
mod increment;
|
||||
mod memcmp;
|
||||
mod xor;
|
||||
|
||||
/// Xors the source into the destination
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass_constant_time::xor;
|
||||
/// use rosenpass_to::To;
|
||||
/// assert_eq!(
|
||||
/// xor(b"world").to_this(|| b"hello".to_vec()),
|
||||
/// b"\x1f\n\x1e\x00\x0b");
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If source and destination are of different sizes.
|
||||
#[inline]
|
||||
pub fn xor(src: &[u8]) -> impl To<[u8], ()> + '_ {
|
||||
with_destination(|dst: &mut [u8]| {
|
||||
assert!(black_box(src.len()) == black_box(dst.len()));
|
||||
for (dv, sv) in dst.iter_mut().zip(src.iter()) {
|
||||
*black_box(dv) ^= black_box(*sv);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
|
||||
a.len() == b.len()
|
||||
&& unsafe { memsec::memeq(a.as_ptr() as *const u8, b.as_ptr() as *const u8, a.len()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn compare(a: &[u8], b: &[u8]) -> i32 {
|
||||
assert!(a.len() == b.len());
|
||||
unsafe { memsec::memcmp(a.as_ptr(), b.as_ptr(), a.len()) }
|
||||
}
|
||||
|
||||
/// Interpret the given slice as a little-endian unsigned integer
|
||||
/// and increment that integer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass_constant_time::increment as inc;
|
||||
/// use rosenpass_to::To;
|
||||
///
|
||||
/// fn testcase(v: &[u8], correct: &[u8]) {
|
||||
/// let mut v = v.to_owned();
|
||||
/// inc(&mut v);
|
||||
/// assert_eq!(&v, correct);
|
||||
/// }
|
||||
///
|
||||
/// testcase(b"", b"");
|
||||
/// testcase(b"\x00", b"\x01");
|
||||
/// testcase(b"\x01", b"\x02");
|
||||
/// testcase(b"\xfe", b"\xff");
|
||||
/// testcase(b"\xff", b"\x00");
|
||||
/// testcase(b"\x00\x00", b"\x01\x00");
|
||||
/// testcase(b"\x01\x00", b"\x02\x00");
|
||||
/// testcase(b"\xfe\x00", b"\xff\x00");
|
||||
/// testcase(b"\xff\x00", b"\x00\x01");
|
||||
/// testcase(b"\x00\x00\x00\x00\x00\x00", b"\x01\x00\x00\x00\x00\x00");
|
||||
/// testcase(b"\x00\xa3\x00\x77\x00\x00", b"\x01\xa3\x00\x77\x00\x00");
|
||||
/// testcase(b"\xff\xa3\x00\x77\x00\x00", b"\x00\xa4\x00\x77\x00\x00");
|
||||
/// testcase(b"\xff\xff\xff\x77\x00\x00", b"\x00\x00\x00\x78\x00\x00");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn increment(v: &mut [u8]) {
|
||||
let mut carry = 1u8;
|
||||
for val in v.iter_mut() {
|
||||
let (v, c) = black_box(*val).overflowing_add(black_box(carry));
|
||||
*black_box(val) = v;
|
||||
*black_box(&mut carry) = black_box(black_box(c) as u8);
|
||||
}
|
||||
}
|
||||
pub use compare::compare;
|
||||
pub use compare::memcmp_le;
|
||||
pub use increment::increment;
|
||||
pub use memcmp::memcmp;
|
||||
pub use xor::xor;
|
||||
|
||||
125
constant-time/src/memcmp.rs
Normal file
125
constant-time/src/memcmp.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
//! memcmp
|
||||
|
||||
/// compares two sclices of memory content and returns whether they are equal
|
||||
///
|
||||
/// ## Leaks
|
||||
/// If the two slices have differents lengths, the function will return immediately. This
|
||||
/// effectively leaks the information whether the slices have equal length or not. This is widely
|
||||
/// considered safe.
|
||||
///
|
||||
/// The execution time of the function grows approx. linear with the length of the input. This is
|
||||
/// considered safe.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass_constant_time::memcmp;
|
||||
/// let a = [0, 0, 0, 0];
|
||||
/// let b = [0, 0, 0, 1];
|
||||
/// let c = [0, 0, 0];
|
||||
/// assert!(memcmp(&a, &a));
|
||||
/// assert!(!memcmp(&a, &b));
|
||||
/// assert!(!memcmp(&a, &c));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
|
||||
a.len() == b.len() && unsafe { memsec::memeq(a.as_ptr(), b.as_ptr(), a.len()) }
|
||||
}
|
||||
|
||||
/// [tests::memcmp_runs_in_constant_time] runs a stasticial test that the equality of the two
|
||||
/// input parameters does not correlate with the run time.
|
||||
///
|
||||
/// For discussion on how to (further) ensure the constant-time execution of this function,
|
||||
/// see <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
#[cfg(all(test, feature = "constant_time_tests"))]
|
||||
// Stopgap measure against https://github.com/rosenpass/rosenpass/issues/634
|
||||
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use core::hint::black_box;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::time::Instant;
|
||||
|
||||
#[test]
|
||||
/// tests whether [memcmp] actually runs in constant time
|
||||
///
|
||||
/// This test function will run an equal amount of comparisons on two different sets of parameters:
|
||||
/// - completely equal slices
|
||||
/// - completely unequal slices.
|
||||
/// All comparisons are executed in a randomized order. The test will fail if one of the
|
||||
/// two sets is checked for equality significantly faster than the other set
|
||||
/// (absolute correlation coefficient ≥ 0.01)
|
||||
fn memcmp_runs_in_constant_time() {
|
||||
// prepare data to compare
|
||||
let n: usize = 1E6 as usize; // number of comparisons to run
|
||||
const LEN: usize = 1024; // length of each slice passed as parameters to the tested comparison function
|
||||
|
||||
let a = [b'a'; LEN];
|
||||
let b = [b'b'; LEN];
|
||||
|
||||
let mut tmp = [0u8; LEN];
|
||||
|
||||
// vector representing all timing tests
|
||||
//
|
||||
// Each element is a tuple of:
|
||||
// 0: whether the test compared two equal slices
|
||||
// 1: the duration needed for the comparison to run
|
||||
let mut tests = (0..n)
|
||||
.map(|i| (i < n / 2, std::time::Duration::ZERO))
|
||||
.collect::<Vec<_>>();
|
||||
tests.shuffle(&mut thread_rng());
|
||||
|
||||
// run comparisons / call function to test
|
||||
for test in tests.iter_mut() {
|
||||
let src = match test.0 {
|
||||
true => a,
|
||||
false => b,
|
||||
};
|
||||
tmp.copy_from_slice(&src);
|
||||
|
||||
let now = Instant::now();
|
||||
memcmp(black_box(&a), black_box(&tmp));
|
||||
test.1 = now.elapsed();
|
||||
// println!("eq: {}, elapsed: {:.2?}", test.0, test.1);
|
||||
}
|
||||
|
||||
// sort by execution time and calculate Pearson correlation coefficient
|
||||
tests.sort_by_key(|v| v.1);
|
||||
let tests = tests
|
||||
.iter()
|
||||
.map(|t| (if t.0 { 1_f64 } else { 0_f64 }, t.1.as_nanos() as f64))
|
||||
.collect::<Vec<_>>();
|
||||
// averages
|
||||
let (avg_x, avg_y): (f64, f64) = (
|
||||
tests.iter().map(|t| t.0).sum::<f64>() / n as f64,
|
||||
tests.iter().map(|t| t.1).sum::<f64>() / n as f64,
|
||||
);
|
||||
assert!((avg_x - 0.5).abs() < 1E-12);
|
||||
// standard deviations
|
||||
let sd_x = 0.5;
|
||||
let sd_y = (1_f64 / n as f64
|
||||
* tests
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let difference = t.1 - avg_y;
|
||||
difference * difference
|
||||
})
|
||||
.sum::<f64>())
|
||||
.sqrt();
|
||||
// covariance
|
||||
let cv = 1_f64 / n as f64
|
||||
* tests
|
||||
.iter()
|
||||
.map(|t| (t.0 - avg_x) * (t.1 - avg_y))
|
||||
.sum::<f64>();
|
||||
// Pearson correlation
|
||||
let correlation = cv / (sd_x * sd_y);
|
||||
println!("correlation: {:.6?}", correlation);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
correlation.abs() < 0.01,
|
||||
"execution time correlates with result"
|
||||
)
|
||||
}
|
||||
}
|
||||
47
constant-time/src/xor.rs
Normal file
47
constant-time/src/xor.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! xor
|
||||
|
||||
use core::hint::black_box;
|
||||
use rosenpass_to::{with_destination, To};
|
||||
|
||||
/// Xors the source into the destination
|
||||
///
|
||||
/// Performs a constant-time XOR operation between two byte slices
|
||||
///
|
||||
/// Takes a source slice and XORs it with the destination slice in-place using the
|
||||
/// rosenpass_to trait for destination management.
|
||||
///
|
||||
/// # Panics
|
||||
/// If source and destination are of different sizes.
|
||||
///
|
||||
/// # Leaks
|
||||
/// This function may leak timing information in the following ways:
|
||||
///
|
||||
/// - The function execution time is linearly proportional to the input length
|
||||
/// - Length mismatches between source and destination are immediately detectable via panic
|
||||
/// - Memory access patterns follow a predictable sequential pattern
|
||||
///
|
||||
/// These leaks are generally considered acceptable in most cryptographic contexts
|
||||
/// as they don't reveal information about the actual content being XORed.
|
||||
///
|
||||
/// ## Tests
|
||||
/// For discussion on how to ensure the constant-time execution of this function, see
|
||||
/// <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass_constant_time::xor;
|
||||
/// use rosenpass_to::To;
|
||||
/// assert_eq!(
|
||||
/// xor(b"world").to_this(|| b"hello".to_vec()),
|
||||
/// b"\x1f\n\x1e\x00\x0b");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn xor(src: &[u8]) -> impl To<[u8], ()> + '_ {
|
||||
with_destination(|dst: &mut [u8]| {
|
||||
assert!(black_box(src.len()) == black_box(dst.len()));
|
||||
for (dv, sv) in dst.iter_mut().zip(src.iter()) {
|
||||
*black_box(dv) ^= black_box(*sv);
|
||||
}
|
||||
})
|
||||
}
|
||||
46
coverage_report.sh
Executable file
46
coverage_report.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
OUTPUT_DIR="target/grcov"
|
||||
|
||||
log() {
|
||||
echo >&2 "$@"
|
||||
}
|
||||
|
||||
exc() {
|
||||
echo '$' "$@"
|
||||
"$@"
|
||||
}
|
||||
|
||||
main() {
|
||||
exc cd "$(dirname "$0")"
|
||||
|
||||
local open="0"
|
||||
if [[ "$1" == "--open" ]]; then
|
||||
open="1"
|
||||
fi
|
||||
|
||||
exc cargo llvm-cov --all-features --workspace --doctests --branch
|
||||
|
||||
exc rm -rf target/llvm-cov-target/debug/deps/doctestbins
|
||||
exc mv -v target/llvm-cov-target/doctestbins target/llvm-cov-target/debug/deps/
|
||||
exc rm -rf "${OUTPUT_DIR}"
|
||||
exc mkdir -p "${OUTPUT_DIR}"
|
||||
exc grcov target/llvm-cov-target/ --llvm -s . --branch \
|
||||
--binary-path ./target/llvm-cov-target/debug/deps \
|
||||
--ignore-not-existing --ignore '../*' --ignore "/*" \
|
||||
--excl-line '^\s*#\[(derive|repr)\(' \
|
||||
-t lcov,html,markdown -o "${OUTPUT_DIR}"
|
||||
|
||||
if (( "${open}" == 1 )); then
|
||||
xdg-open "${PWD}/${OUTPUT_DIR}/html/index.html"
|
||||
fi
|
||||
|
||||
log ""
|
||||
log "Generated reports in \"${PWD}/${OUTPUT_DIR}\"."
|
||||
log "Open \"${PWD}/${OUTPUT_DIR}/html/index.html\" to view HTML report."
|
||||
log ""
|
||||
}
|
||||
|
||||
main "$@"
|
||||
121
deny.toml
Normal file
121
deny.toml
Normal file
@@ -0,0 +1,121 @@
|
||||
# The graph table configures how the dependency graph is constructed and thus
|
||||
# which crates the checks are performed against
|
||||
[graph]
|
||||
# If true, metadata will be collected with `--all-features`. Note that this can't
|
||||
# be toggled off if true, if you want to conditionally enable `--all-features` it
|
||||
# is recommended to pass `--all-features` on the cmd line instead
|
||||
all-features = true
|
||||
# If true, metadata will be collected with `--no-default-features`. The same
|
||||
# caveat with `all-features` applies
|
||||
no-default-features = false
|
||||
|
||||
# The output table provides options for how/if diagnostics are outputted
|
||||
[output]
|
||||
# When outputting inclusion graphs in diagnostics that include features, this
|
||||
# option can be used to specify the depth at which feature edges will be added.
|
||||
# This option is included since the graphs can be quite large and the addition
|
||||
# of features from the crate(s) to all of the graph roots can be far too verbose.
|
||||
# This option can be overridden via `--feature-depth` on the cmd line
|
||||
feature-depth = 1
|
||||
|
||||
# This section is considered when running `cargo deny check advisories`
|
||||
# More documentation for the advisories section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
||||
[advisories]
|
||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||
# output a note when they are encountered.
|
||||
ignore = ["RUSTSEC-2024-0370", "RUSTSEC-2024-0436", "RUSTSEC-2023-0089"]
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
|
||||
# See Git Authentication for more information about setting up git authentication.
|
||||
#git-fetch-with-cli = true
|
||||
|
||||
# This section is considered when running `cargo deny check #licenses`
|
||||
# More documentation for the licenses section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
||||
[licenses]
|
||||
# List of explicitly allowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
allow = [
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
]
|
||||
# The confidence threshold for detecting a license from license text.
|
||||
# The higher the value, the more closely the license text must be to the
|
||||
# canonical license text of a valid SPDX license file.
|
||||
# [possible values: any between 0.0 and 1.0].
|
||||
confidence-threshold = 0.8
|
||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||
# aren't accepted for every possible crate as with the normal allow list
|
||||
exceptions = [
|
||||
# Each entry is the crate and version constraint, and its specific allow
|
||||
# list
|
||||
{ allow = ["Unicode-DFS-2016", "Unicode-3.0"], crate = "unicode-ident" },
|
||||
{ allow = ["NCSA"], crate = "libfuzzer-sys" },
|
||||
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
# If true, ignores workspace crates that aren't published, or are only
|
||||
# published to private registries.
|
||||
# To see how to mark a crate as unpublished (to the official registry),
|
||||
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
|
||||
ignore = true
|
||||
|
||||
# This section is considered when running `cargo deny check bans`.
|
||||
# More documentation about the 'bans' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
||||
[bans]
|
||||
# Lint level for when multiple versions of the same crate are detected
|
||||
multiple-versions = "warn"
|
||||
# Lint level for when a crate version requirement is `*`
|
||||
wildcards = "allow"
|
||||
# The graph highlighting used when creating dotgraphs for crates
|
||||
# with multiple versions
|
||||
# * lowest-version - The path to the lowest versioned duplicate is highlighted
|
||||
# * simplest-path - The path to the version with the fewest edges is highlighted
|
||||
# * all - Both lowest-version and simplest-path are used
|
||||
highlight = "all"
|
||||
# The default lint level for `default` features for crates that are members of
|
||||
# the workspace that is being checked. This can be overridden by allowing/denying
|
||||
# `default` on a crate-by-crate basis if desired.
|
||||
workspace-default-features = "allow"
|
||||
# The default lint level for `default` features for external crates that are not
|
||||
# members of the workspace. This can be overridden by allowing/denying `default`
|
||||
# on a crate-by-crate basis if desired.
|
||||
external-default-features = "allow"
|
||||
# List of crates that are allowed. Use with care!
|
||||
allow = []
|
||||
# List of crates to deny
|
||||
deny = []
|
||||
|
||||
skip-tree = []
|
||||
|
||||
# This section is considered when running `cargo deny check sources`.
|
||||
# More documentation about the 'sources' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
||||
[sources]
|
||||
# Lint level for what to happen when a crate from a crate registry that is not
|
||||
# in the allow list is encountered
|
||||
unknown-registry = "warn"
|
||||
# Lint level for what to happen when a crate from a git repository that is not
|
||||
# in the allow list is encountered
|
||||
unknown-git = "warn"
|
||||
# List of URLs for allowed crate registries. Defaults to the crates.io index
|
||||
# if not specified. If it is specified but empty, no registries are allowed.
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
# List of URLs for allowed Git repositories
|
||||
allow-git = ["git+https://github.com/rosenpass/memsec.git?branch=master"]
|
||||
|
||||
[sources.allow-org]
|
||||
# github.com organizations to allow git sources for
|
||||
github = []
|
||||
# gitlab.com organizations to allow git sources for
|
||||
gitlab = []
|
||||
# bitbucket.org organizations to allow git sources for
|
||||
bitbucket = []
|
||||
13
doc/check.sh
Executable file
13
doc/check.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# We have to filter this STYLE error out, because it is very platform specific
|
||||
OUTPUT=$(mandoc -Tlint "$1" | grep --invert-match "STYLE: referenced manual not found")
|
||||
|
||||
if [ -z "$OUTPUT" ]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
echo "$1 is malformatted, check mandoc -Tlint $1"
|
||||
echo "$OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
114
doc/rosenpass.1
114
doc/rosenpass.1
@@ -1,114 +0,0 @@
|
||||
.Dd $Mdocdate$
|
||||
.Dt ROSENPASS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rosenpass
|
||||
.Nd builds post-quantum-secure VPNs
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op COMMAND
|
||||
.Op Ar OPTIONS ...
|
||||
.Op Ar ARGS ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
performs cryptographic key exchanges that are secure against quantum-computers
|
||||
and then outputs the keys.
|
||||
These keys can then be passed to various services, such as wireguard or other
|
||||
vpn services, as pre-shared-keys to achieve security against attackers with
|
||||
quantum computers.
|
||||
.Pp
|
||||
This is a research project and quantum computers are not thought to become
|
||||
practical in fewer than ten years.
|
||||
If you are not specifically tasked with developing post-quantum secure systems,
|
||||
you probably do not need this tool.
|
||||
.Ss COMMANDS
|
||||
.Bl -tag -width Ds
|
||||
.It Ar gen-keys --secret-key <file-path> --public-key <file-path>
|
||||
Generate a keypair to use in the exchange command later.
|
||||
Send the public-key file to your communication partner and keep the private-key
|
||||
file secret!
|
||||
.It Ar exchange private-key <file-path> public-key <file-path> [ OPTIONS ] PEERS
|
||||
Start a process to exchange keys with the specified peers.
|
||||
You should specify at least one peer.
|
||||
.Pp
|
||||
Its
|
||||
.Ar OPTIONS
|
||||
are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Ar listen <ip>[:<port>]
|
||||
Instructs
|
||||
.Nm
|
||||
to listen on the specified interface and port.
|
||||
By default,
|
||||
.Nm
|
||||
will listen on all interfaces and select a random port.
|
||||
.It Ar verbose
|
||||
Extra logging.
|
||||
.El
|
||||
.El
|
||||
.Ss PEER
|
||||
Each
|
||||
.Ar PEER
|
||||
is defined as follows:
|
||||
.Qq peer public-key <file-path> [endpoint <ip>[:<port>]] [preshared-key <file-path>] [outfile <file-path>] [wireguard <dev> <peer> <extra_params>]
|
||||
.Pp
|
||||
Providing a
|
||||
.Ar PEER
|
||||
instructs
|
||||
.Nm
|
||||
to exchange keys with the given peer and write the resulting PSK into the given
|
||||
output file.
|
||||
You must either specify the outfile or wireguard output option.
|
||||
.Pp
|
||||
The parameters of
|
||||
.Ar PEER
|
||||
are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Ar endpoint <ip>[:<port>]
|
||||
Specifies the address where the peer can be reached.
|
||||
This will be automatically updated after the first successful key exchange with
|
||||
the peer.
|
||||
If this is unspecified, the peer must initiate the connection.
|
||||
.It Ar preshared-key <file-path>
|
||||
You may specify a pre-shared key which will be mixed into the final secret.
|
||||
.It Ar outfile <file-path>
|
||||
You may specify a file to write the exchanged keys to.
|
||||
If this option is specified,
|
||||
.Nm
|
||||
will write a notification to standard out every time the key is updated.
|
||||
.It Ar wireguard <dev> <peer> <extra_params>
|
||||
This allows you to directly specify a wireguard peer to deploy the
|
||||
pre-shared-key to.
|
||||
You may specify extra parameters you would pass to
|
||||
.Qq wg set
|
||||
besides the preshared-key parameter which is used by
|
||||
.Nm .
|
||||
This makes it possible to add peers entirely from
|
||||
.Nm .
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr rp 1 ,
|
||||
.Xr wg 1
|
||||
.Rs
|
||||
.%A Karolin Varner
|
||||
.%A Benjamin Lipp
|
||||
.%A Wanja Zaeske
|
||||
.%A Lisa Schmidt
|
||||
.%D 2023
|
||||
.%T Rosenpass
|
||||
.%U https://rosenpass.eu/whitepaper.pdf
|
||||
.Re
|
||||
.Sh STANDARDS
|
||||
This tool is the reference implementation of the Rosenpass protocol, as
|
||||
specified within the whitepaper referenced above.
|
||||
.Sh AUTHORS
|
||||
Rosenpass was created by Karolin Varner, Benjamin Lipp, Wanja Zaeske,
|
||||
Marei Peischl, Stephan Ajuvo, and Lisa Schmidt.
|
||||
.Pp
|
||||
This manual page was written by
|
||||
.An Emil Engler
|
||||
.Sh BUGS
|
||||
The bugs are tracked at
|
||||
.Lk https://github.com/rosenpass/rosenpass/issues .
|
||||
2
doc/rp.1
2
doc/rp.1
@@ -113,7 +113,7 @@ Rosenpass was created by Karolin Varner, Benjamin Lipp, Wanja Zaeske,
|
||||
Marei Peischl, Stephan Ajuvo, and Lisa Schmidt.
|
||||
.Pp
|
||||
This manual page was written by
|
||||
.An Emil Engler
|
||||
.An Clara Engler
|
||||
.Sh BUGS
|
||||
The bugs are tracked at
|
||||
.Lk https://github.com/rosenpass/rosenpass/issues .
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
# Multi Device Isolation
|
||||
|
||||
On supported systems (just Linux, state Feb. 2024), Rosenpass uses a so-called broker architecture where multiple operating system processes work together to negotiate a key using post quantum cryptography and then send it to WireGuard to run an actual VPN. This is similar to the sandboxes used by web browsers to prevent websites accessing the rest of the computer.
|
||||
|
||||
These processes communicate using what is called a "unix socket"; a special file that can be used by to processes to send data back and forth. There are tools to forward data from a unix socket one one host to a unix socket on another host. By using one of these tools, you can run most of Rosenpass' processes on one host while running just the process that forwards keys from Rosenpass to WireGuard on the device that establishes the WireGuard tunnel.
|
||||
|
||||
This type of setup can provide a very high degree of isolation. When set up correctly, a critical bug in the Rosenpass code can not affect the host running WireGuard and vice versa. Keep in mind though that for this goal to be reached, the method to connect both hosts must be sufficiently secured: If the WireGuard host is allowed to perform arbitrary commands on the Rosenpass host, then an attacker with access to the WireGuard device can also take over the Rosenpass device.
|
||||
|
||||
You can use the instructions from [Unix Domain Socket Forwarding with OpenSSH](https://www.skreutz.com/posts/unix-domain-socket-forwarding-with-openssh/) to harden the connection between the two devices after following the instructions from this tutorial.
|
||||
|
||||
## Instructions
|
||||
|
||||
In this manual, we are dealing with three hosts:
|
||||
|
||||
- The **local peer**: The local host running WireGuard
|
||||
- The **remote peer**: The remote host we are connecting to.
|
||||
- The **the rosenpass device**: The dedicated host running rosenpass. It connects with *local peer* to supply WireGuard with keys and it connects with remote peer to perform key exchanges.
|
||||
|
||||
Lets assume, that you are starting from a working Rosenpass setup on *local peer* and *remote peer*, running rosenpass and WireGuard on each host. Both setups use configuration files. We will move the rosenpass instance running on *local peer* to the *rosenpass device* in this tutorial.
|
||||
|
||||
### Step 0: Setup Rosenpass
|
||||
|
||||
If you do not have a functioning rosenpass deployment on the local and remote peer at this point, you can create one by using the configuration files from the configuration-examples directory.
|
||||
|
||||
You will need to set up the WireGuard device manually using instructions for your linux distribution. You can use the tutorial on the [arch wiki](https://wiki.archlinux.org/title/WireGuard) for reference.
|
||||
|
||||
Make sure to set a random pre-shared key during creation of the WireGuard setup on both hosts at startup. Random pre-shared keys can be generated by using `wg genpks` on each host.
|
||||
|
||||
For the broker based setup to work, you might have to assign the broker process the CAP_NET_ADMIN linux capability:
|
||||
|
||||
```bash
|
||||
sudo setcap CAP_NET_ADMIN=+eip ./target/debug/rosenpass-wireguard-broker-privileged
|
||||
```
|
||||
|
||||
Make sure the broker binaries are in your system path when starting rosenpass:
|
||||
|
||||
```bash
|
||||
PATH="$PWD/target/debug:$PATH" ./target/debug/rosenpass exchange-config ./path/to/config/file.toml
|
||||
```
|
||||
|
||||
You will also need to setup rosenpass on the rosenpass device.
|
||||
|
||||
### Step 1: Verify that your rosenpass setup is working
|
||||
|
||||
Start rosenpass on both peers using the following command.
|
||||
|
||||
```bash
|
||||
PATH="$PWD/target/debug:$PATH" rosenpass exchange-config ./path/to/config/file.toml
|
||||
```
|
||||
|
||||
Now you can verify that rosenpass inserted a pre-shared key on both hosts:
|
||||
|
||||
```bash
|
||||
wg show wgRpTest preshared-keys
|
||||
```
|
||||
|
||||
The shell output will look similar to this:
|
||||
|
||||
```
|
||||
tdnV/wa/0Uf8Nrm3cZkKXOm4atrOEPzv1+dvaG7p7y0= 5235LJ/ONgrO8XuxECtLPzGOyWSvuzHcexzcgoHubfs=
|
||||
```
|
||||
|
||||
The first value is the peer's public key, the second in the pre-shared key. The pre-shared keys should match.
|
||||
|
||||
### Step 2: Manually start the broker
|
||||
|
||||
Rosenpass starts the psk-broker internally by default. We are looking to manually start it instead.
|
||||
|
||||
On the *local peer*, first start the broker manually:
|
||||
|
||||
```bash
|
||||
rm -fv broker.sock; PATH="target/debug" ./target/debug/rosenpass-wireguard-broker-socket-handler --listen-path broker.sock
|
||||
```
|
||||
|
||||
Now you should call rosenpass while make use of the created socket. Use the `psk_broker` configuration key. Your configuration will now look something like this:
|
||||
|
||||
```bash
|
||||
PATH="$PWD/target/debug:$PATH" rosenpass --psk-broker broker.sock exchange-config ./path/to/config/file.toml
|
||||
```
|
||||
|
||||
### Step 2: Forward the unix socket to the rosenpass device
|
||||
|
||||
OpenSSH socket forwarding can be used; on the local peer you can execute something like the following command:
|
||||
|
||||
```bash
|
||||
ssh -vgMR path/to/rosenpass/broker.sock:./broker.sock -L user@rosenpass_device
|
||||
```
|
||||
|
||||
### Step 3: Start rosenpass on the rosenpass device
|
||||
|
||||
You may need to copy your configuration files to the rosenpass device:
|
||||
|
||||
```bash
|
||||
scp ./path/to/config/file.toml ./path/to/peer/pk ./path/to/pk ./path/to/sk user@rosenpass_device:path/to/rosenpass/
|
||||
```
|
||||
|
||||
Now you can start rosenpass on the rosenpass device:
|
||||
|
||||
```bash
|
||||
PATH="$PWD/target/debug:$PATH" ./target/debug/rosenpass exchange-config ./path/to/config.toml
|
||||
```
|
||||
|
||||
### Step 4: Harden the setup
|
||||
|
||||
This tutorial is in a very rough state; it currently provides enough hints to advanced users to convey how the setup is supposed work. For a real production setup it needs to be adapted.
|
||||
|
||||
In particular, you can use the guide from from [Unix Domain Socket Forwarding with OpenSSH](https://www.skreutz.com/posts/unix-domain-socket-forwarding-with-openssh/) to make sure neither the *local peer* nor the *rosenpass device* can execute arbitrary commands on each other. The socat tutorial used in this setup can be used to achieve a diversity of setups, such as forwarding the unix socket via a plain TCP socket without encryption to the rosenpass device, if a trusted network setup is used to connect the two. Other setups such as securing the connection using TLS or forwarding the connection via a serial connection can be achieved.
|
||||
|
||||
You should also make sure that the rosenpass secret key is at no point in time stored in the *local peer*, so if you followed this tutorial you might want to regenerate the keypair on the *rosenpass device* itself.
|
||||
46
docker/Dockerfile
Normal file
46
docker/Dockerfile
Normal file
@@ -0,0 +1,46 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG BASE_IMAGE=debian:bookworm-slim
|
||||
ARG CHEF_IMAGE=rust:slim-bookworm
|
||||
|
||||
# Stage 1: Base image with cargo-chef installed
|
||||
FROM ${CHEF_IMAGE} AS chef
|
||||
RUN cargo install cargo-chef
|
||||
# install software required for liboqs-rust
|
||||
RUN apt-get update && apt-get install -y clang cmake && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Stage 2: Prepare the cargo-chef recipe
|
||||
FROM chef AS planner
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
# Stage 3: Cache dependencies using the recipe
|
||||
FROM chef AS cacher
|
||||
WORKDIR /app
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
|
||||
# Stage 4: Build the application
|
||||
FROM cacher AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN cargo build --release
|
||||
|
||||
# Stage 5: Install runtime-dependencies in the base image
|
||||
FROM ${BASE_IMAGE} AS base_image_with_dependencies
|
||||
|
||||
RUN apt-get update && apt-get install -y iproute2 && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Final Stage (rosenpass): Copy the rosenpass binary
|
||||
FROM base_image_with_dependencies AS rosenpass
|
||||
COPY --from=builder /app/target/release/rosenpass /usr/local/bin/rosenpass
|
||||
ENTRYPOINT [ "/usr/local/bin/rosenpass" ]
|
||||
|
||||
# Final Stage (rp): Copy the rp binary
|
||||
FROM base_image_with_dependencies AS rp
|
||||
|
||||
RUN apt-get update && apt-get install -y wireguard && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /app/target/release/rp /usr/local/bin/rp
|
||||
ENTRYPOINT [ "/usr/local/bin/rp" ]
|
||||
203
docker/USAGE.md
Normal file
203
docker/USAGE.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Rosenpass in Docker
|
||||
|
||||
Rosenpass provides post-quantum-secure key exchange for VPNs. It generates symmetric keys used by [WireGuard](https://www.wireguard.com/papers/wireguard.pdf) or other applications. The protocol enhances "Post-Quantum WireGuard" ([PQWG](https://eprint.iacr.org/2020/379)) with a cookie mechanism for better security against state disruption attacks.
|
||||
|
||||
Prebuilt Docker images are available for easy deployment:
|
||||
|
||||
- [`ghcr.io/rosenpass/rosenpass`](https://github.com/rosenpass/rosenpass/pkgs/container/rosenpass) – the core key exchange tool
|
||||
- [`ghcr.io/rosenpass/rp`](https://github.com/rosenpass/rosenpass/pkgs/container/rp) – a frontend for setting up WireGuard VPNs
|
||||
|
||||
The entrypoint of the `rosenpass` image is the `rosenpass` executable, whose documentation can be found [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp_manual/).
|
||||
Similarly, the entrypoint of the `rp` image is the `rp` executable, with its documentation available [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp1/).
|
||||
|
||||
## Usage - Standalone Key Exchange
|
||||
|
||||
The `ghcr.io/rosenpass/rosenpass` image can be used in a server-client setup to exchange quantum-secure shared keys.
|
||||
This setup uses rosenpass as a standalone application, without using any other component such as wireguard.
|
||||
What follows, is a simple setup for illustrative purposes.
|
||||
|
||||
Create a docker network that is used to connect the containers:
|
||||
|
||||
```bash
|
||||
docker network create -d bridge rp
|
||||
export NET=rp
|
||||
```
|
||||
|
||||
Generate the server and client key pairs:
|
||||
|
||||
```bash
|
||||
mkdir ./workdir-client ./workdir-server
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
gen-keys --public-key=workdir/server-public --secret-key=workdir/server-secret
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
gen-keys --public-key=workdir/client-public --secret-key=workdir/client-secret
|
||||
# share the public keys between client and server
|
||||
cp workdir-client/client-public workdir-server/client-public
|
||||
cp workdir-server/server-public workdir-client/server-public
|
||||
```
|
||||
|
||||
Start the server container:
|
||||
|
||||
```bash
|
||||
docker run --name "rpserver" --network ${NET} \
|
||||
-it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
exchange \
|
||||
private-key workdir/server-secret \
|
||||
public-key workdir/server-public \
|
||||
listen 0.0.0.0:9999 \
|
||||
peer public-key workdir/client-public \
|
||||
outfile workdir/server-sharedkey
|
||||
```
|
||||
|
||||
Find out the ip address of the server container:
|
||||
|
||||
```bash
|
||||
EP="rpserver"
|
||||
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
|
||||
```
|
||||
|
||||
Run the client container and perform the key exchange:
|
||||
|
||||
```bash
|
||||
docker run --name "rpclient" --network ${NET} \
|
||||
-it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
exchange \
|
||||
private-key workdir/client-secret \
|
||||
public-key workdir/client-public \
|
||||
peer public-key workdir/server-public endpoint ${EP}:9999 \
|
||||
outfile workdir/client-sharedkey
|
||||
```
|
||||
|
||||
Now the containers will exchange shared keys and each put them into their respective outfile.
|
||||
|
||||
Comparing the outfiles shows that these shared keys equal:
|
||||
|
||||
```bash
|
||||
cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
|
||||
```
|
||||
|
||||
It is now possible to set add these keys as pre-shared keys within a wireguard interface.
|
||||
For example as the server,
|
||||
|
||||
```bash
|
||||
PREKEY=$(cat workdir-server/server-sharedkey)
|
||||
wg set <server-interface> peer <client-peer-public-key> preshared-key <(echo "$PREKEY")
|
||||
```
|
||||
|
||||
## Usage - Combined with wireguard
|
||||
|
||||
The `ghcr.io/rosenpass/rp` image can be used to build a VPN with WireGuard and Rosenpass.
|
||||
In this example, we run two containers on the same system and connect them with a bridge network within the docker overlay network.
|
||||
|
||||
Create the named docker network, to be able to connect the containers.
|
||||
|
||||
Create a docker network that is used to connect the containers:
|
||||
|
||||
```bash
|
||||
docker network create -d bridge rp
|
||||
export NET=rp
|
||||
```
|
||||
|
||||
Generate the server and client secret keys and extract public keys.
|
||||
|
||||
```bash
|
||||
mkdir -p ./workdir-server ./workdir-client
|
||||
|
||||
# server
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
|
||||
genkey workdir/server.rosenpass-secret
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
|
||||
pubkey workdir/server.rosenpass-secret workdir/server.rosenpass-public
|
||||
|
||||
# client
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
|
||||
genkey workdir/client.rosenpass-secret
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
|
||||
pubkey workdir/client.rosenpass-secret workdir/client.rosenpass-public
|
||||
|
||||
# share the public keys between client and server
|
||||
cp -r workdir-client/client.rosenpass-public workdir-server/client.rosenpass-public
|
||||
cp -r workdir-server/server.rosenpass-public workdir-client/server.rosenpass-public
|
||||
```
|
||||
|
||||
Start the server container.
|
||||
Note that the `NET_ADMIN` capability is neccessary, the rp command will create and manage wireguard interfaces.
|
||||
Also make sure the `wireguard` kernel module is loaded by the host. (`lsmod | grep wireguard`)
|
||||
|
||||
```bash
|
||||
docker run --name "rpserver" --network ${NET} -it -d --rm -v ./workdir-server:/workdir \
|
||||
--cap-add=NET_ADMIN \
|
||||
ghcr.io/rosenpass/rp \
|
||||
exchange workdir/server.rosenpass-secret dev rosenpass0 \
|
||||
listen 0.0.0.0:9999 peer workdir/client.rosenpass-public allowed-ips 10.0.0.0/8
|
||||
```
|
||||
|
||||
Now find out the ip-address of the server container and then start the client container:
|
||||
|
||||
```bash
|
||||
EP="rpserver"
|
||||
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
|
||||
docker run --name "rpclient" --network ${NET} -it -d --rm -v ./workdir-client:/workdir \
|
||||
--cap-add=NET_ADMIN \
|
||||
ghcr.io/rosenpass/rp \
|
||||
exchange workdir/client.rosenpass-secret dev rosenpass1 \
|
||||
peer workdir/server.rosenpass-public endpoint ${EP}:9999 allowed-ips 10.0.0.1
|
||||
```
|
||||
|
||||
Inside the docker containers assign the IP addresses:
|
||||
|
||||
```bash
|
||||
# server
|
||||
docker exec -it rpserver ip a add 10.0.0.1/24 dev rosenpass0
|
||||
|
||||
# client
|
||||
docker exec -it rpclient ip a add 10.0.0.2/24 dev rosenpass1
|
||||
```
|
||||
|
||||
Done! The two containers should now be connected through a wireguard VPN (Port 1000) with pre-shared keys exchanged by rosenpass (Port 9999).
|
||||
|
||||
Now, test the connection by starting a shell inside the client container, and ping the server through the VPN:
|
||||
|
||||
```bash
|
||||
# client
|
||||
docker exec -it rpclient bash
|
||||
apt update; apt install iputils-ping
|
||||
ping 10.0.0.1
|
||||
```
|
||||
|
||||
The ping command should continuously show ping-logs:
|
||||
|
||||
```
|
||||
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
|
||||
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.119 ms
|
||||
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.132 ms
|
||||
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.394 ms
|
||||
...
|
||||
```
|
||||
|
||||
While the ping is running, you may stop the server container, and verify that the ping-log halts. In another terminal do:
|
||||
|
||||
```
|
||||
docker stop -t 1 rpserver
|
||||
```
|
||||
|
||||
## Building the Docker Images Locally
|
||||
|
||||
Clone the Rosenpass repository:
|
||||
|
||||
```
|
||||
git clone https://github.com/rosenpass/rosenpass
|
||||
cd rosenpass
|
||||
```
|
||||
|
||||
Build the rp image from the root of the repository as follows:
|
||||
|
||||
```
|
||||
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rp --target rp .
|
||||
```
|
||||
|
||||
Build the rosenpass image from the root of the repostiry with the following command:
|
||||
|
||||
```
|
||||
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rosenpass --target rosenpass .
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
public_key = "./pk1"
|
||||
secret_key = "./sk1"
|
||||
listen = ["[::]:9999"]
|
||||
verbosity = "Verbose"
|
||||
|
||||
[[peers]]
|
||||
public_key = "./pk2"
|
||||
device = "YOUR WIREGUARD DEVICE"
|
||||
peer = "YOUR PEER PK"
|
||||
@@ -1,26 +0,0 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
rosenpass:
|
||||
build: ../rosenpass/
|
||||
command: rosenpass
|
||||
ports:
|
||||
- name: rosenpass-ipv4
|
||||
target: 9999
|
||||
host_ip: 127.0.0.1
|
||||
published: 9999
|
||||
protocol: udp
|
||||
mode: host
|
||||
- name: rosenpass-ipv4
|
||||
target: 9999
|
||||
host_ip: '[::1]'
|
||||
published: 9999
|
||||
protocol: udp
|
||||
mode: host
|
||||
environment:
|
||||
RUST_LOG: info
|
||||
#DEBUG_ENTRYPOINT: 1
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
volumes:
|
||||
- ../socket:/socket:ro
|
||||
- ../config:/config:ro
|
||||
@@ -1,14 +0,0 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
rosenpass:
|
||||
build: ../rosenpass
|
||||
command: psk_broker
|
||||
environment:
|
||||
RUST_LOG: info
|
||||
USER_GAINS_CAP_NET_ADMIN: 1
|
||||
#DEBUG_ENTRYPOINT: 1
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
volumes:
|
||||
- ../socket:/socket:rw
|
||||
network_mode: host
|
||||
@@ -1,35 +0,0 @@
|
||||
FROM rust:slim as build
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
libclang-dev \
|
||||
libcap2-bin \
|
||||
git \
|
||||
inotify-tools
|
||||
|
||||
RUN adduser --system --uid 768 --group rosenpass --home /var/lib/rosenpass
|
||||
|
||||
USER rosenpass:rosenpass
|
||||
RUN cd ~rosenpass \
|
||||
&& git clone --depth 1 "https://github.com/rosenpass/rosenpass" -b dev/broker-architecture rosenpass-source \
|
||||
&& cd rosenpass-source \
|
||||
&& mkdir -p ~rosenpass/usr \
|
||||
&& cargo install --path rosenpass --root ~rosenpass/usr --bins \
|
||||
&& cargo install --path wireguard-broker --root ~rosenpass/usr --bins \
|
||||
&& cd ~rosenpass \
|
||||
&& rm -R rosenpass-source
|
||||
USER root:root
|
||||
|
||||
# TODO: Is this proper handling of ambient capabilities?
|
||||
RUN setcap CAP_NET_ADMIN=+ep ~rosenpass/usr/bin/rosenpass-wireguard-broker-privileged
|
||||
|
||||
VOLUME /config
|
||||
COPY ./entrypoint.sh /usr/local/sbin/docker_entrypoint
|
||||
COPY ./fd_passing.pl /usr/local/sbin/fd_passing
|
||||
RUN chmod a+x /usr/local/sbin/docker_entrypoint /usr/local/sbin/fd_passing
|
||||
ENTRYPOINT ["/usr/local/sbin/docker_entrypoint"]
|
||||
|
||||
VOLUME /socket
|
||||
|
||||
CMD rosenpass config.toml
|
||||
@@ -1,187 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -e # Needed by bail()
|
||||
|
||||
log() {
|
||||
local lvl; lvl="${1}"; shift || bail "log()" "USAGE: log LEVEL CONTEXT MSG..."
|
||||
local ctx; ctx="${1}"; shift || bail "log()" "USAGE: log LEVEL CONTEXT MSG..."
|
||||
echo >&2 "[entrypoint.sh/${ctx} ${lvl}]:" "$@"
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [[ -n "${DEBUG_ENTRYPOINT}" ]]; then
|
||||
log "DEBUG" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
log_info() {
|
||||
log "INFO" "$@"
|
||||
}
|
||||
|
||||
log_err() {
|
||||
log "ERROR" "$@"
|
||||
}
|
||||
|
||||
exc() {
|
||||
local ctx; ctx="${1}"; shift || bail "exc()" "USAGE: exc CONTEXT CMD..."
|
||||
log_debug '$' "$@"
|
||||
"$@"
|
||||
}
|
||||
|
||||
bail() {
|
||||
local ctx; ctx="${1}"; shift || bail "bail()" "USAGE: bail CONTEXT MSG..."
|
||||
(( "$#" != 0 )) || bail "${ctx}" $'USAGE: bail CONTEXT MSG... # Bail called without parameters! Please use error messages dear developer.'
|
||||
log_err "${ctx}" "$@"
|
||||
return 1
|
||||
}
|
||||
|
||||
join() {
|
||||
local delim; delim="$1"; shift || bail "join()" "USAGE: join DELIM ELMS..."
|
||||
local tmp fst
|
||||
fst="true"
|
||||
for tmp in "$@"; do
|
||||
if [[ "${fst}" = "true" ]]; then
|
||||
printf "%s" "${tmp}"
|
||||
fst=""
|
||||
else
|
||||
printf "%s%s" "${delim}" "${tmp}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Shred files after they where red (recursively)
|
||||
# USAGE: $ burn_after_reading DIR
|
||||
burn_after_reading() {
|
||||
local dir; dir="$1"; shift || bail "join()" "USAGE: burn_after_reading DIR"
|
||||
|
||||
log_info burn_after_reading "Started for ${dir}"
|
||||
|
||||
# Load the list of configuration files
|
||||
local -a files_arr # Array
|
||||
readarray -td $'\0' files_arr < <(find "${dir}" -type f -print0)
|
||||
|
||||
# Convert configuration file list to associative array
|
||||
local file
|
||||
local -A files_todo # Associative array
|
||||
for file in "${files_arr[@]}"; do
|
||||
files_todo["${file}"]="1"
|
||||
done
|
||||
|
||||
# Watch for closed files
|
||||
local file
|
||||
# The --exclude '/$' excludes directories
|
||||
inotifywait --quiet --monitor --event close_nowrite --exclude '/$' --recursive . --no-newline --format "%w%f%0" \
|
||||
| while read -d $'\0' -r file; do
|
||||
|
||||
# Check if the file is in the todo list, if yes, erase it
|
||||
if [[ "${files_todo["${file}"]+1}" = "1" ]]; then
|
||||
log_info burn_after_reading "File loaded from configuration; removing now: ${file}";
|
||||
shred "${file}"
|
||||
# Clear from the todo list; What in the devils name is this quoting style bash
|
||||
unset 'files_todo["${file}"]'
|
||||
fi
|
||||
|
||||
# We're done if the todo list is empty
|
||||
if (( "${#files_todo[@]}" == 0 )); then
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
as_user() {
|
||||
local -a cmd_prefix
|
||||
if [[ "$1" = "--exec" ]]; then
|
||||
cmd_prefix=("exec")
|
||||
shift
|
||||
fi
|
||||
|
||||
local user; user="$1"; shift || bail "as_user()" "USAGE: as_user USER CMD..."
|
||||
(( "$#" > 0 )) || bail "as_user()" "USAGE: as_user USER CMD..."
|
||||
|
||||
if [[ -n "${USER_GAINS_CAP_NET_ADMIN}" ]]; then # TODO: Dirty to do this here; use --cap-net-admin or something?
|
||||
exc "as_user()" "${cmd_prefix[@]}" \
|
||||
capsh --caps="cap_net_admin+eip cap_setuid,cap_setgid+ep" --keep=1 \
|
||||
--user="${user}" --addamb=cap_net_admin -- -c 'exec "$@"' -- "$@"
|
||||
elif [[ "${user}" = "$(whoami)" ]]; then
|
||||
exc "as_user()" "${cmd_prefix[@]}" "$@"
|
||||
else
|
||||
exc "as_user()" "${cmd_prefix[@]}" runuser -u "${user}" -- "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
bail "USAGE: ${SCRIPT} rosenpass|psk_broker"
|
||||
}
|
||||
|
||||
cmd_internal() {
|
||||
"$@"
|
||||
}
|
||||
|
||||
cmd_run_command() {
|
||||
exc "run_command()" as_user --exec "${SWITCH_USER}" "$@"
|
||||
}
|
||||
|
||||
cmd_psk_broker() {
|
||||
exc "psk_broker()" exec \
|
||||
fd_passing --listen /socket/psk_broker.sock \
|
||||
"$SCRIPT" internal as_user --exec "${SWITCH_USER}" \
|
||||
rosenpass-wireguard-broker-socket-handler --listen-fd
|
||||
}
|
||||
|
||||
rosenpass_start_with_socket_fd() {
|
||||
local fd; fd="$1"; shift || bail "rosenpass_start_with_socket_fd()" "USAGE: rosenpass_start_with_socket_fd PSK_BROKER_FD"
|
||||
exc "rosenpass_start_with_socket_fd()" exec \
|
||||
rosenpass --psk-broker-fd "$fd" exchange-config /config/config.toml
|
||||
}
|
||||
|
||||
cmd_rosenpass() {
|
||||
test -z "${USER_GAINS_CAP_NET_ADMIN}" || bail "rosenpass()" "USER_GAINS_CAP_NET_ADMIN should be unset. The rosenpass instance doing key exchanges should not have network admin privileges!"
|
||||
exc "psk_broker()" exec \
|
||||
fd_passing --connect /socket/psk_broker.sock \
|
||||
"$SCRIPT" internal as_user --exec "${SWITCH_USER}" \
|
||||
"$SCRIPT" internal rosenpass_start_with_socket_fd
|
||||
}
|
||||
|
||||
main() {
|
||||
local command; command="$1"; shift || usage
|
||||
case "${command}" in
|
||||
internal) cmd_internal "$@" ;;
|
||||
run_command) ;;
|
||||
psk_broker) ;;
|
||||
rosenpass) ;;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
exc "main()" umask u=rw,og=
|
||||
exc "main()" cp -R "${CONFIG_MOUNT}" "${CONFIG_TMP}"
|
||||
exc "main()" chmod -R u+X "${CONFIG_TMP}"
|
||||
exc "main()" chown -R rosenpass:rosenpass "${CONFIG_TMP}"
|
||||
# TODO: How can we do this? We should probably use a dedicated config broker.
|
||||
#exc "main()" umount "${CONFIG_MOUNT}"
|
||||
exc "main()" cd "${CONFIG_TMP}"
|
||||
|
||||
if [[ -n "${BURN_AFTER_READING}" ]]; then
|
||||
( burn_after_reading /dev/shm/rosenpass-config )&
|
||||
fi
|
||||
|
||||
local -a path_cpy extra_path_cpy
|
||||
mapfile -td ':' path_cpy < <(echo -n "$PATH")
|
||||
mapfile -td ':' extra_path_cpy < <(echo -n "$EXTRA_PATH")
|
||||
PATH="$(join ":" "${extra_path_cpy[@]}" "${path_cpy[@]}")"
|
||||
export PATH
|
||||
|
||||
exc "main()" "cmd_${command}" "$@"
|
||||
}
|
||||
|
||||
SCRIPT="$0"
|
||||
|
||||
# Config
|
||||
CONFIG_MOUNT="${CONFIG_MOUNT:-/config}"
|
||||
CONFIG_TMP="${CONFIG_TMP:-/dev/shm/rosenpass-config}"
|
||||
BURN_AFTER_READING="${BURN_AFTER_READING:-true}"
|
||||
SWITCH_USER="${SWITCH_USER:-rosenpass}"
|
||||
#USER_GAINS_CAP_NET_ADMIN="${USER_GAINS_CAP_NET_ADMIN}"
|
||||
EXTRA_PATH="${EXTRA_PATH:-"$(eval echo ~rosenpass)/usr/bin"}"
|
||||
|
||||
main "$@"
|
||||
@@ -1,38 +0,0 @@
|
||||
#! /usr/bin/perl
|
||||
|
||||
use Fcntl;
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
my $usage = "[$0] Usage: $0 SOCKETPATH [--connect|--listen] CMD...";
|
||||
|
||||
my $mode = shift or die($usage);
|
||||
my $sopath = shift or die($usage);
|
||||
|
||||
|
||||
my $listen;
|
||||
if ($mode eq "--listen") {
|
||||
$listen = 1;
|
||||
} elsif ($mode eq "--connect") {
|
||||
$listen = 0;
|
||||
} else {
|
||||
die($usage);
|
||||
}
|
||||
|
||||
my $socket;
|
||||
if ($listen == 1) {
|
||||
$socket = IO::Socket::UNIX->new(
|
||||
Type => SOCK_STREAM(),
|
||||
Local => $sopath,
|
||||
Listen => 1,
|
||||
) or die "[$0] Error listening on socket socket: $!";
|
||||
} else {
|
||||
$socket = IO::Socket::UNIX->new(
|
||||
Type => SOCK_STREAM(),
|
||||
Peer => $sopath,
|
||||
) or die "[$0] Error listening on socket socket: $!";
|
||||
}
|
||||
|
||||
my $fd_flags = $socket->fcntl(F_GETFD, 0) or die "[$0] fcntl F_GETFD: $!";
|
||||
$socket->fcntl(F_SETFD, $fd_flags & ~FD_CLOEXEC) or die "[$0] fcntl F_SETFD: $!";
|
||||
|
||||
exec(@ARGV, $socket->fileno); # pass it on the command line
|
||||
227
flake.lock
generated
227
flake.lock
generated
@@ -1,36 +1,15 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699770036,
|
||||
"narHash": "sha256-bZmI7ytPAYLpyFNgj5xirDkKuAniOkj1xHdv5aIJ5GM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "81ab0b4f7ae9ebb57daa0edf119c4891806e4d3a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -39,62 +18,154 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"naersk": {
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698420672,
|
||||
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1698846319,
|
||||
"narHash": "sha256-4jyW/dqFBVpWFnhl0nvP6EN4lP7/ZqPxYRjl6var0Oc=",
|
||||
"lastModified": 1728193676,
|
||||
"narHash": "sha256-PbDWAIjKJdlVg+qQRhzdSor04bAPApDqIv2DofTyynk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "34bdaaf1f0b7fb6d9091472edc968ff10a8c2857",
|
||||
"rev": "ecbc1ca8ffd6aea8372ad16be9ebbb39889e55b6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nix-vm-test": "nix-vm-test",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rosenpassOld": "rosenpassOld",
|
||||
"rust-overlay": "rust-overlay_2",
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"rosenpassOld": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nix-vm-test": "nix-vm-test_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699715108,
|
||||
"narHash": "sha256-yPozsobJU55gj+szgo4Lpcg1lHvGQYAT6Y4MrC80mWE=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "5fcf5289e726785d20d3aa4d13d90a43ed248e83",
|
||||
"lastModified": 1754748821,
|
||||
"narHash": "sha256-mMggTZDC97lLvKNOLtDz3GBjjxXFD++e1s0RZsVH/vI=",
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"owner": "rosenpass",
|
||||
"repo": "rosenpass",
|
||||
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -112,6 +183,62 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"rosenpassOld",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
538
flake.nix
538
flake.nix
@@ -1,367 +1,247 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
# for quicker rust builds
|
||||
naersk.url = "github:nix-community/naersk";
|
||||
naersk.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nix-vm-test.url = "github:numtide/nix-vm-test";
|
||||
nix-vm-test.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nix-vm-test.inputs.flake-utils.follows = "flake-utils";
|
||||
|
||||
# for rust nightly with llvm-tools-preview
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
# Older version of rosenpass, referenced here for backwards compatibility
|
||||
rosenpassOld.url = "github:rosenpass/rosenpass?rev=916a9ebb7133f0b22057fb097a473217f261928a";
|
||||
rosenpassOld.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, ... }@inputs:
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
nix-vm-test,
|
||||
rust-overlay,
|
||||
treefmt-nix,
|
||||
rosenpassOld,
|
||||
...
|
||||
}@inputs:
|
||||
nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [
|
||||
|
||||
#
|
||||
### Export the overlay.nix from this flake ###
|
||||
#
|
||||
{ overlays.default = import ./overlay.nix; }
|
||||
|
||||
#
|
||||
### Actual Rosenpass Package and Docker Container Images ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(system:
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(
|
||||
system:
|
||||
let
|
||||
scoped = (scope: scope.result);
|
||||
lib = nixpkgs.lib;
|
||||
|
||||
# normal nixpkgs
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
|
||||
# TODO remove overlay once a fix for
|
||||
# https://github.com/NixOS/nixpkgs/issues/216904 got merged
|
||||
overlays = [
|
||||
(
|
||||
final: prev: {
|
||||
iproute2 = prev.iproute2.overrideAttrs (old:
|
||||
let
|
||||
isStatic = prev.stdenv.hostPlatform.isStatic;
|
||||
in
|
||||
{
|
||||
makeFlags = old.makeFlags ++ prev.lib.optional isStatic [
|
||||
"TC_CONFIG_NO_XT=y"
|
||||
];
|
||||
});
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
# parsed Cargo.toml
|
||||
cargoToml = builtins.fromTOML (builtins.readFile ./rosenpass/Cargo.toml);
|
||||
|
||||
# source files relevant for rust
|
||||
src = scoped rec {
|
||||
# File suffices to include
|
||||
extensions = [
|
||||
"lock"
|
||||
"rs"
|
||||
"toml"
|
||||
];
|
||||
# Files to explicitly include
|
||||
files = [
|
||||
"to/README.md"
|
||||
];
|
||||
|
||||
src = ./.;
|
||||
filter = (path: type: scoped rec {
|
||||
inherit (lib) any id removePrefix hasSuffix;
|
||||
anyof = (any id);
|
||||
|
||||
basename = baseNameOf (toString path);
|
||||
relative = removePrefix (toString src + "/") (toString path);
|
||||
|
||||
result = anyof [
|
||||
(type == "directory")
|
||||
(any (ext: hasSuffix ".${ext}" basename) extensions)
|
||||
(any (file: file == relative) files)
|
||||
];
|
||||
});
|
||||
|
||||
result = pkgs.lib.sources.cleanSourceWith { inherit src filter; };
|
||||
};
|
||||
|
||||
# builds a bin path for all dependencies for the `rp` shellscript
|
||||
rpBinPath = p: with p; lib.makeBinPath [
|
||||
coreutils
|
||||
findutils
|
||||
gawk
|
||||
wireguard-tools
|
||||
];
|
||||
|
||||
# a function to generate a nix derivation for rosenpass against any
|
||||
# given set of nixpkgs
|
||||
rpDerivation = p:
|
||||
let
|
||||
# whether we want to build a statically linked binary
|
||||
isStatic = p.targetPlatform.isStatic;
|
||||
|
||||
# the rust target of `p`
|
||||
target = p.rust.toRustTargetSpec p.targetPlatform;
|
||||
|
||||
# convert a string to shout case
|
||||
shout = string: builtins.replaceStrings [ "-" ] [ "_" ] (pkgs.lib.toUpper string);
|
||||
|
||||
# suitable Rust toolchain
|
||||
toolchain = with inputs.fenix.packages.${system}; combine [
|
||||
stable.cargo
|
||||
stable.rustc
|
||||
targets.${target}.stable.rust-std
|
||||
];
|
||||
|
||||
# naersk with a custom toolchain
|
||||
naersk = pkgs.callPackage inputs.naersk {
|
||||
cargo = toolchain;
|
||||
rustc = toolchain;
|
||||
};
|
||||
|
||||
# used to trick the build.rs into believing that CMake was ran **again**
|
||||
fakecmake = pkgs.writeScriptBin "cmake" ''
|
||||
#! ${pkgs.stdenv.shell} -e
|
||||
true
|
||||
'';
|
||||
in
|
||||
naersk.buildPackage
|
||||
{
|
||||
# metadata and source
|
||||
name = cargoToml.package.name;
|
||||
version = cargoToml.package.version;
|
||||
inherit src;
|
||||
|
||||
cargoBuildOptions = x: x ++ [ "-p" "rosenpass" ];
|
||||
cargoTestOptions = x: x ++ [ "-p" "rosenpass" ];
|
||||
|
||||
doCheck = true;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
p.stdenv.cc
|
||||
cmake # for oqs build in the oqs-sys crate
|
||||
mandoc # for the built-in manual
|
||||
makeWrapper # for the rp shellscript
|
||||
pkg-config # let libsodium-sys-stable find libsodium
|
||||
removeReferencesTo
|
||||
rustPlatform.bindgenHook # for C-bindings in the crypto libs
|
||||
];
|
||||
buildInputs = with p; [ bash libsodium ];
|
||||
|
||||
override = x: {
|
||||
preBuild =
|
||||
# nix defaults to building for aarch64 _without_ the armv8-a crypto
|
||||
# extensions, but liboqs depens on these
|
||||
(lib.optionalString (system == "aarch64-linux") ''
|
||||
NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -march=armv8-a+crypto"
|
||||
''
|
||||
);
|
||||
|
||||
# fortify is only compatible with dynamic linking
|
||||
hardeningDisable = lib.optional isStatic "fortify";
|
||||
};
|
||||
|
||||
overrideMain = x: {
|
||||
# CMake detects that it was served a _foreign_ target dir, and CMake
|
||||
# would be executed again upon the second build step of naersk.
|
||||
# By adding our specially optimized CMake version, we reduce the cost
|
||||
# of recompilation by 99 % while, while avoiding any CMake errors.
|
||||
nativeBuildInputs = [ (lib.hiPrio fakecmake) ] ++ x.nativeBuildInputs;
|
||||
|
||||
# make sure that libc is linked, under musl this is not the case per
|
||||
# default
|
||||
preBuild = (lib.optionalString isStatic ''
|
||||
NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -lc"
|
||||
'');
|
||||
|
||||
preInstall = ''
|
||||
install -D ${./rp} $out/bin/rp
|
||||
wrapProgram $out/bin/rp --prefix PATH : "${ rpBinPath p }"
|
||||
'';
|
||||
};
|
||||
|
||||
# We want to build for a specific target...
|
||||
CARGO_BUILD_TARGET = target;
|
||||
|
||||
# ... which might require a non-default linker:
|
||||
"CARGO_TARGET_${shout target}_LINKER" =
|
||||
let
|
||||
inherit (p.stdenv) cc;
|
||||
in
|
||||
"${cc}/bin/${cc.targetPrefix}cc";
|
||||
|
||||
meta = with pkgs.lib;
|
||||
{
|
||||
inherit (cargoToml.package) description homepage;
|
||||
license = with licenses; [ mit asl20 ];
|
||||
maintainers = [ maintainers.wucke13 ];
|
||||
platforms = platforms.all;
|
||||
};
|
||||
} // (lib.mkIf isStatic {
|
||||
# otherwise pkg-config tries to link non-existent dynamic libs
|
||||
# documented here: https://docs.rs/pkg-config/latest/pkg_config/
|
||||
PKG_CONFIG_ALL_STATIC = true;
|
||||
|
||||
# tell rust to build everything statically linked
|
||||
CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
|
||||
});
|
||||
# a function to generate a docker image based of rosenpass
|
||||
rosenpassOCI = name: pkgs.dockerTools.buildImage rec {
|
||||
inherit name;
|
||||
copyToRoot = pkgs.buildEnv {
|
||||
name = "image-root";
|
||||
paths = [ self.packages.${system}.${name} ];
|
||||
pathsToLink = [ "/bin" ];
|
||||
};
|
||||
config.Cmd = [ "/bin/rosenpass" ];
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
overlays = [ self.overlays.default ];
|
||||
};
|
||||
in
|
||||
rec {
|
||||
packages = rec {
|
||||
default = rosenpass;
|
||||
rosenpass = rpDerivation pkgs;
|
||||
rosenpass-oci-image = rosenpassOCI "rosenpass";
|
||||
{
|
||||
packages =
|
||||
{
|
||||
default = pkgs.rosenpass;
|
||||
rosenpass = pkgs.rosenpass;
|
||||
rosenpass-oci-image = pkgs.rosenpass-oci-image;
|
||||
rp = pkgs.rp;
|
||||
|
||||
# derivation for the release
|
||||
release-package =
|
||||
let
|
||||
version = cargoToml.package.version;
|
||||
package =
|
||||
if pkgs.hostPlatform.isLinux then
|
||||
packages.rosenpass-static
|
||||
else packages.rosenpass;
|
||||
oci-image =
|
||||
if pkgs.hostPlatform.isLinux then
|
||||
packages.rosenpass-static-oci-image
|
||||
else packages.rosenpass-oci-image;
|
||||
in
|
||||
pkgs.runCommandNoCC "lace-result" { }
|
||||
''
|
||||
mkdir {bin,$out}
|
||||
cp ${./.}/rp bin/
|
||||
tar -cvf $out/rosenpass-${system}-${version}.tar bin/rp \
|
||||
-C ${package} bin/rosenpass
|
||||
cp ${oci-image} \
|
||||
$out/rosenpass-oci-image-${system}-${version}.tar.gz
|
||||
'';
|
||||
} // (if pkgs.stdenv.isLinux then rec {
|
||||
rosenpass-static = rpDerivation pkgs.pkgsStatic;
|
||||
rosenpass-static-oci-image = rosenpassOCI "rosenpass-static";
|
||||
} else { });
|
||||
release-package = pkgs.release-package;
|
||||
|
||||
# for good measure, we also offer to cross compile to Linux on Arm
|
||||
aarch64-linux-rosenpass-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rosenpass;
|
||||
aarch64-linux-rp-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rp;
|
||||
}
|
||||
//
|
||||
# We only offer static builds for linux, as this is not supported on OS X
|
||||
(nixpkgs.lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
|
||||
rosenpass-static = pkgs.pkgsStatic.rosenpass;
|
||||
rosenpass-static-oci-image = pkgs.pkgsStatic.rosenpass-oci-image;
|
||||
rp-static = pkgs.pkgsStatic.rp;
|
||||
});
|
||||
}
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
#
|
||||
### Linux specifics ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
packages = self.packages.${system};
|
||||
in
|
||||
{
|
||||
#
|
||||
### Whitepaper ###
|
||||
#
|
||||
packages.whitepaper =
|
||||
let
|
||||
tlsetup = (pkgs.texlive.combine {
|
||||
inherit (pkgs.texlive) scheme-basic acmart amsfonts ccicons
|
||||
csquotes csvsimple doclicense fancyvrb fontspec gobble
|
||||
koma-script ifmtarg latexmk lm markdown mathtools minted noto
|
||||
nunito pgf soul unicode-math lualatex-math paralist
|
||||
gitinfo2 eso-pic biblatex biblatex-trad biblatex-software
|
||||
xkeyval xurl xifthen biber;
|
||||
});
|
||||
in
|
||||
pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "whitepaper";
|
||||
src = ./papers;
|
||||
nativeBuildInputs = with pkgs; [
|
||||
ncurses # tput
|
||||
python3Packages.pygments
|
||||
tlsetup # custom tex live scheme
|
||||
which
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"i686-linux"
|
||||
]
|
||||
(
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
|
||||
overlays = [
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
self.overlays.default
|
||||
|
||||
nix-vm-test.overlays.default
|
||||
|
||||
# apply rust-overlay to get specific versions of the rust toolchain for a MSRV check
|
||||
(import rust-overlay)
|
||||
];
|
||||
buildPhase = ''
|
||||
export HOME=$(mktemp -d)
|
||||
latexmk -r tex/CI.rc
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
mv *.pdf readme.md $out/
|
||||
'';
|
||||
};
|
||||
|
||||
treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;
|
||||
in
|
||||
{
|
||||
packages.package-deb = pkgs.callPackage ./pkgs/package-deb.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
packages.package-rpm = pkgs.callPackage ./pkgs/package-rpm.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif.overrideAttrs (old: {
|
||||
postInstall = ''
|
||||
install -D -t $out/lib cryptoverif.pvl
|
||||
'';
|
||||
});
|
||||
packages.proof-proverif = pkgs.stdenv.mkDerivation {
|
||||
name = "rosenpass-proverif-proof";
|
||||
version = "unstable";
|
||||
src = pkgs.lib.sources.sourceByRegex ./. [
|
||||
"analyze.sh"
|
||||
"marzipan(/marzipan.awk)?"
|
||||
"analysis(/.*)?"
|
||||
];
|
||||
nativeBuildInputs = [ pkgs.proverif pkgs.graphviz ];
|
||||
CRYPTOVERIF_LIB = packages.proverif-patched + "/lib/cryptoverif.pvl";
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
bash analyze.sh -color -html $out
|
||||
'';
|
||||
};
|
||||
#
|
||||
### Reading materials ###
|
||||
#
|
||||
packages.whitepaper = pkgs.whitepaper;
|
||||
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif-patched;
|
||||
packages.proof-proverif = pkgs.proof-proverif;
|
||||
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (packages.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ packages.default ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake # override the fakecmake from the main step above
|
||||
cargo-release
|
||||
clippy
|
||||
nodePackages.prettier
|
||||
rustfmt
|
||||
packages.proverif-patched
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ packages.default ];
|
||||
nativeBuildInputs = with pkgs; [ inputs.fenix.packages.${system}.complete.toolchain cargo-llvm-cov ];
|
||||
};
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
];
|
||||
};
|
||||
# TODO: Write this as a patched version of the default environment
|
||||
devShells.fullEnv = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-audit
|
||||
cargo-msrv
|
||||
cargo-release
|
||||
cargo-vet
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rust-bin.stable.latest.complete
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = [
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rustc.llvmPackages.llvm
|
||||
];
|
||||
env = {
|
||||
inherit (pkgs.cargo-llvm-cov) LLVM_COV LLVM_PROFDATA;
|
||||
};
|
||||
};
|
||||
devShells.benchmarks = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
];
|
||||
};
|
||||
# a devshell to hunt unsafe `unsafe` in the code
|
||||
devShells.miri = pkgs.mkShell {
|
||||
# inputsFrom = [ self.packages.${system}.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
((rust-bin.selectLatestNightlyWith (toolchain: toolchain.default)).override {
|
||||
extensions = [
|
||||
"rust-analysis"
|
||||
"rust-src"
|
||||
"miri-preview"
|
||||
];
|
||||
})
|
||||
pkgs.cmake
|
||||
pkgs.rustPlatform.bindgenHook
|
||||
];
|
||||
# Run this to find unsafe `unsafe`:
|
||||
# MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --no-fail-fast --lib --bins --tests
|
||||
#
|
||||
# - Some test failure is expected.
|
||||
};
|
||||
|
||||
checks =
|
||||
import ./tests/integration/integration-checks.nix {
|
||||
inherit system;
|
||||
pkgs = inputs.nixpkgs;
|
||||
lib = nixpkgs.lib;
|
||||
rosenpassNew = self.packages.${system}.default;
|
||||
rosenpassOld = rosenpassOld.packages.${system}.default;
|
||||
}
|
||||
// {
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
formatting = treefmtEval.config.build.check self;
|
||||
rosenpass-msrv-check =
|
||||
let
|
||||
rosenpassCargoToml = pkgs.lib.trivial.importTOML ./rosenpass/Cargo.toml;
|
||||
|
||||
checks = {
|
||||
cargo-fmt = pkgs.runCommand "check-cargo-fmt"
|
||||
{ inherit (self.devShells.${system}.default) nativeBuildInputs buildInputs; } ''
|
||||
cargo fmt --manifest-path=${./.}/Cargo.toml --check --all && touch $out
|
||||
'';
|
||||
nixpkgs-fmt = pkgs.runCommand "check-nixpkgs-fmt"
|
||||
{ nativeBuildInputs = [ pkgs.nixpkgs-fmt ]; } ''
|
||||
nixpkgs-fmt --check ${./.} && touch $out
|
||||
'';
|
||||
prettier-check = pkgs.runCommand "check-with-prettier"
|
||||
{ nativeBuildInputs = [ pkgs.nodePackages.prettier ]; } ''
|
||||
cd ${./.} && prettier --check . && touch $out
|
||||
'';
|
||||
};
|
||||
rustToolchain = pkgs.rust-bin.stable.${rosenpassCargoToml.package.rust-version}.default;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = rustToolchain;
|
||||
rustc = rustToolchain;
|
||||
};
|
||||
in
|
||||
pkgs.rosenpass.override { inherit rustPlatform; };
|
||||
}
|
||||
// pkgs.lib.optionalAttrs (system == "x86_64-linux") (
|
||||
import ./tests/legacy-distro-packaging.nix {
|
||||
inherit pkgs;
|
||||
rosenpass-deb = self.packages.${system}.package-deb;
|
||||
rosenpass-rpm = self.packages.${system}.package-rpm;
|
||||
}
|
||||
);
|
||||
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
}))
|
||||
# for `nix fmt`
|
||||
formatter = treefmtEval.config.build.wrapper;
|
||||
}
|
||||
)
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ name = "rosenpass-fuzzing"
|
||||
version = "0.0.1"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
@@ -48,13 +52,37 @@ test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_box_secret_alloc"
|
||||
path = "fuzz_targets/box_secret_alloc.rs"
|
||||
name = "fuzz_box_secret_alloc_malloc"
|
||||
path = "fuzz_targets/box_secret_alloc_malloc.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_vec_secret_alloc"
|
||||
path = "fuzz_targets/vec_secret_alloc.rs"
|
||||
name = "fuzz_vec_secret_alloc_malloc"
|
||||
path = "fuzz_targets/vec_secret_alloc_malloc.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_box_secret_alloc_memfdsec"
|
||||
path = "fuzz_targets/box_secret_alloc_memfdsec.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_vec_secret_alloc_memfdsec"
|
||||
path = "fuzz_targets/vec_secret_alloc_memfdsec.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_box_secret_alloc_memfdsec_mallocfb"
|
||||
path = "fuzz_targets/box_secret_alloc_memfdsec_mallocfb.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_vec_secret_alloc_memfdsec_mallocfb"
|
||||
path = "fuzz_targets/vec_secret_alloc_memfdsec_mallocfb.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
@@ -4,7 +4,8 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_ciphers::aead;
|
||||
use rosenpass_cipher_traits::primitives::Aead as _;
|
||||
use rosenpass_ciphers::Aead;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Debug)]
|
||||
pub struct Input {
|
||||
@@ -15,10 +16,9 @@ pub struct Input {
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
let mut ciphertext: Vec<u8> = Vec::with_capacity(input.plaintext.len() + 16);
|
||||
ciphertext.resize(input.plaintext.len() + 16, 0);
|
||||
let mut ciphertext = vec![0u8; input.plaintext.len() + 16];
|
||||
|
||||
aead::encrypt(
|
||||
Aead.encrypt(
|
||||
ciphertext.as_mut_slice(),
|
||||
&input.key,
|
||||
&input.nonce,
|
||||
|
||||
@@ -4,6 +4,7 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashTo;
|
||||
use rosenpass_ciphers::subtle::blake2b;
|
||||
use rosenpass_to::To;
|
||||
|
||||
@@ -16,5 +17,7 @@ pub struct Blake2b {
|
||||
fuzz_target!(|input: Blake2b| {
|
||||
let mut out = [0u8; 32];
|
||||
|
||||
blake2b::hash(&input.key, &input.data).to(&mut out).unwrap();
|
||||
blake2b::Blake2b::keyed_hash_to(&input.key, &input.data)
|
||||
.to(&mut out)
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
12
fuzz/fuzz_targets/box_secret_alloc_malloc.rs
Normal file
12
fuzz/fuzz_targets/box_secret_alloc_malloc.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use rosenpass_secret_memory::alloc::secret_box;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
use std::sync::Once;
|
||||
static ONCE: Once = Once::new();
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
ONCE.call_once(secret_policy_use_only_malloc_secrets);
|
||||
let _ = secret_box(data);
|
||||
});
|
||||
13
fuzz/fuzz_targets/box_secret_alloc_memfdsec.rs
Normal file
13
fuzz/fuzz_targets/box_secret_alloc_memfdsec.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use rosenpass_secret_memory::alloc::secret_box;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
use std::sync::Once;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
ONCE.call_once(secret_policy_use_only_memfd_secrets);
|
||||
let _ = secret_box(data);
|
||||
});
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use rosenpass_secret_memory::alloc::secret_box;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
use std::sync::Once;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
ONCE.call_once(secret_policy_try_use_memfd_secrets);
|
||||
let _ = secret_box(data);
|
||||
});
|
||||
@@ -4,11 +4,17 @@ extern crate rosenpass;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass::protocol::CryptoServer;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
use rosenpass_secret_memory::{PublicBox, Secret};
|
||||
use std::sync::Once;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
fuzz_target!(|rx_buf: &[u8]| {
|
||||
let sk = Secret::from_slice(&[0; 13568]);
|
||||
let pk = Secret::from_slice(&[0; 524160]);
|
||||
ONCE.call_once(secret_policy_use_only_malloc_secrets);
|
||||
let sk = Secret::from_slice(&[0; StaticKem::SK_LEN]);
|
||||
let pk = PublicBox::from_slice(&[0; StaticKem::PK_LEN]);
|
||||
|
||||
let mut cs = CryptoServer::new(sk, pk);
|
||||
let mut tx_buf = [0; 10240];
|
||||
|
||||
@@ -4,17 +4,19 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::EphemeralKem;
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::EphemeralKem;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Debug)]
|
||||
pub struct Input {
|
||||
pub pk: [u8; 800],
|
||||
pub pk: [u8; EphemeralKem::PK_LEN],
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
let mut ciphertext = [0u8; 768];
|
||||
let mut shared_secret = [0u8; 32];
|
||||
let mut ciphertext = [0u8; EphemeralKem::CT_LEN];
|
||||
let mut shared_secret = [0u8; EphemeralKem::SHK_LEN];
|
||||
|
||||
EphemeralKem::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
|
||||
EphemeralKem
|
||||
.encaps(&mut shared_secret, &mut ciphertext, &input.pk)
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
@@ -3,13 +3,13 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
|
||||
fuzz_target!(|input: [u8; StaticKem::PK_LEN]| {
|
||||
let mut ciphertext = [0u8; 188];
|
||||
let mut shared_secret = [0u8; 32];
|
||||
let mut ciphertext = [0u8; StaticKem::CT_LEN];
|
||||
let mut shared_secret = [0u8; StaticKem::SHK_LEN];
|
||||
|
||||
// We expect errors while fuzzing therefore we do not check the result.
|
||||
let _ = StaticKem::encaps(&mut shared_secret, &mut ciphertext, &input);
|
||||
let _ = StaticKem.encaps(&mut shared_secret, &mut ciphertext, &input);
|
||||
});
|
||||
|
||||
15
fuzz/fuzz_targets/vec_secret_alloc_malloc.rs
Normal file
15
fuzz/fuzz_targets/vec_secret_alloc_malloc.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![no_main]
|
||||
|
||||
use std::sync::Once;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use rosenpass_secret_memory::alloc::secret_vec;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
ONCE.call_once(secret_policy_use_only_malloc_secrets);
|
||||
let mut vec = secret_vec();
|
||||
vec.extend_from_slice(data);
|
||||
});
|
||||
15
fuzz/fuzz_targets/vec_secret_alloc_memfdsec.rs
Normal file
15
fuzz/fuzz_targets/vec_secret_alloc_memfdsec.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![no_main]
|
||||
|
||||
use std::sync::Once;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use rosenpass_secret_memory::alloc::secret_vec;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
ONCE.call_once(secret_policy_use_only_memfd_secrets);
|
||||
let mut vec = secret_vec();
|
||||
vec.extend_from_slice(data);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user