mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Compare commits
1105 Commits
v2.0.0-rc1
...
v2.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
780ebb4680 | ||
|
|
02a579af59 | ||
|
|
9bcf1c4b8d | ||
|
|
dec9b4f7c7 | ||
|
|
4701842829 | ||
|
|
488b4bdbe8 | ||
|
|
c8d886b422 | ||
|
|
a83bbd2e92 | ||
|
|
c3a47cb72f | ||
|
|
0971e55d4d | ||
|
|
6f45c7a8ac | ||
|
|
c567d852a5 | ||
|
|
0b38128e21 | ||
|
|
b9daa8b2ee | ||
|
|
878c7173c3 | ||
|
|
f69b980dcf | ||
|
|
33378792ca | ||
|
|
c7a2b4d5e3 | ||
|
|
4a077fc2c9 | ||
|
|
f309ec21d7 | ||
|
|
e261cf7481 | ||
|
|
fa8390b23e | ||
|
|
af89858d47 | ||
|
|
e6a3569743 | ||
|
|
604abec333 | ||
|
|
790666ffb0 | ||
|
|
c9f6ccff9f | ||
|
|
02b3f42500 | ||
|
|
e10724accb | ||
|
|
5b68dec43a | ||
|
|
9d13da0050 | ||
|
|
1e94425279 | ||
|
|
fc48f9bc08 | ||
|
|
2eb25910a1 | ||
|
|
1dab341b33 | ||
|
|
1f7ed87e6c | ||
|
|
c59ea422cc | ||
|
|
0bcb71f742 | ||
|
|
7e38a3386e | ||
|
|
c25b5ef215 | ||
|
|
72fb507de2 | ||
|
|
45c4c95b98 | ||
|
|
e8861d1043 | ||
|
|
c48fcb743b | ||
|
|
d5d732ddf4 | ||
|
|
f83bd5cdf6 | ||
|
|
76c87c628f | ||
|
|
fa125a354d | ||
|
|
f184b54796 | ||
|
|
75925fb2f7 | ||
|
|
b780228ade | ||
|
|
91c012eff0 | ||
|
|
05d45c6948 | ||
|
|
a2c13fbc48 | ||
|
|
16c7aab99b | ||
|
|
0cf5e309a0 | ||
|
|
b5fbd682f2 | ||
|
|
90e04b0046 | ||
|
|
329f6562c2 | ||
|
|
852bad1ef4 | ||
|
|
aa44a61ab2 | ||
|
|
3e237cb490 | ||
|
|
7b206fb13d | ||
|
|
8f7e898341 | ||
|
|
7499d9f245 | ||
|
|
ba6e6f051a | ||
|
|
d4f4dfb54f | ||
|
|
3e7dedaf99 | ||
|
|
f18cd7ae81 | ||
|
|
0ae4fcf8eb | ||
|
|
d3d1e30c7c | ||
|
|
47d0cf495d | ||
|
|
2e883f9d91 | ||
|
|
af0c30e3ea | ||
|
|
da5a35356a | ||
|
|
d98cc3bb6c | ||
|
|
9697f17b9d | ||
|
|
ce3a9d172d | ||
|
|
4448ddc488 | ||
|
|
b77d3c66ae | ||
|
|
2debdfead5 | ||
|
|
b168c65fa1 | ||
|
|
2b46d171db | ||
|
|
64c131d132 | ||
|
|
678a251858 | ||
|
|
bf9d2f6cb0 | ||
|
|
61f5dcb11e | ||
|
|
e4387d2bd1 | ||
|
|
48906f354e | ||
|
|
1ddc098e43 | ||
|
|
165e6c234c | ||
|
|
1be631f43f | ||
|
|
f5f34c2f50 | ||
|
|
33f3619e98 | ||
|
|
3720b66d00 | ||
|
|
864bbc5472 | ||
|
|
080566a1fd | ||
|
|
d9766037a3 | ||
|
|
02821adc47 | ||
|
|
7b08fd4b7d | ||
|
|
0505c70be2 | ||
|
|
f247038e65 | ||
|
|
d7667e9e6e | ||
|
|
188cb114af | ||
|
|
35c49ababf | ||
|
|
faafe09bd0 | ||
|
|
a0e87c9420 | ||
|
|
d9d39f1812 | ||
|
|
82af225742 | ||
|
|
919f4df1a7 | ||
|
|
71a1698bf2 | ||
|
|
a987dd95b8 | ||
|
|
ab6ab8e65c | ||
|
|
3b28d66410 | ||
|
|
eee46ef2f4 | ||
|
|
3c189b4183 | ||
|
|
fd5ab0edf7 | ||
|
|
420387a7a5 | ||
|
|
fc740f8b6d | ||
|
|
834059ddfa | ||
|
|
5ec2fbcd38 | ||
|
|
2fbf5cd79f | ||
|
|
64ebe95751 | ||
|
|
77109b3a33 | ||
|
|
b43429e684 | ||
|
|
97e39f0744 | ||
|
|
fad592b512 | ||
|
|
565de3c536 | ||
|
|
c802269ea3 | ||
|
|
06268963fb | ||
|
|
2227797691 | ||
|
|
f0888c1fe0 | ||
|
|
eda2e62589 | ||
|
|
494d8ec04c | ||
|
|
bb8088ca0f | ||
|
|
26f4bc39fc | ||
|
|
025e4d9fc6 | ||
|
|
b2774d57ba | ||
|
|
51edfb4ec9 | ||
|
|
79019b1ced | ||
|
|
bc87140b5b | ||
|
|
1c5251069b | ||
|
|
0b6dfefcec | ||
|
|
a9e32c55c0 | ||
|
|
a494228407 | ||
|
|
9932b5fc5c | ||
|
|
966ba44a33 | ||
|
|
62c872eb49 | ||
|
|
434fee2e13 | ||
|
|
d3f829c065 | ||
|
|
83934bdcf3 | ||
|
|
3691add163 | ||
|
|
cc7a9e4607 | ||
|
|
943fa69da6 | ||
|
|
3bef291184 | ||
|
|
7316c53b04 | ||
|
|
5e1d1e1850 | ||
|
|
e52c8e148c | ||
|
|
7eb47f3db1 | ||
|
|
ec59d31d04 | ||
|
|
ddd15b63b2 | ||
|
|
e91b35a53d | ||
|
|
fb4079aa4d | ||
|
|
48b203a134 | ||
|
|
2746fd708f | ||
|
|
684f43d84d | ||
|
|
6b1be52e6b | ||
|
|
de6258d366 | ||
|
|
5e4dbf33be | ||
|
|
b03cb3f3d8 | ||
|
|
e08401a2ec | ||
|
|
0a9e7028ae | ||
|
|
ba0ecc54df | ||
|
|
6920f9dc27 | ||
|
|
ba2547212e | ||
|
|
bbe1a8a5b6 | ||
|
|
c82728f04d | ||
|
|
cc0d33bca7 | ||
|
|
3933ec7dce | ||
|
|
f8c9507612 | ||
|
|
7c5c9ae8fd | ||
|
|
cd00792fe9 | ||
|
|
df390509b2 | ||
|
|
dd6abe9375 | ||
|
|
a3f199d0a3 | ||
|
|
8e3b85ee12 | ||
|
|
e60fbfc865 | ||
|
|
a512488fd7 | ||
|
|
1981d909cf | ||
|
|
ea14f2c98c | ||
|
|
c81becf10d | ||
|
|
1433d040ae | ||
|
|
206b70c837 | ||
|
|
bb857dcef2 | ||
|
|
5568a780a9 | ||
|
|
7c2086967b | ||
|
|
f7fbf4d38c | ||
|
|
0c8cf5c1e0 | ||
|
|
33f2af1c09 | ||
|
|
c9a7e6e4ec | ||
|
|
86bb4ea8f2 | ||
|
|
99c4e83994 | ||
|
|
ca2f5a8160 | ||
|
|
7af304251e | ||
|
|
15f5126296 | ||
|
|
21edd66892 | ||
|
|
3e9d6b6960 | ||
|
|
62b580904b | ||
|
|
c4c4f9d159 | ||
|
|
67a5ec1567 | ||
|
|
c646832bfe | ||
|
|
539d4756f2 | ||
|
|
8714e115ad | ||
|
|
9c38e09ad3 | ||
|
|
5628d7d8b5 | ||
|
|
5f2e8d6062 | ||
|
|
630e336ea0 | ||
|
|
430852736d | ||
|
|
4eeb741358 | ||
|
|
bb1ce4a069 | ||
|
|
5e3e4a225e | ||
|
|
583d05e32a | ||
|
|
2c0914b2ba | ||
|
|
3ebedfe7b0 | ||
|
|
1af2f85d43 | ||
|
|
0395e8935a | ||
|
|
7ffd182197 | ||
|
|
fae1abdea9 | ||
|
|
f17b8ad550 | ||
|
|
883b600617 | ||
|
|
f26a9abddb | ||
|
|
4a7180a4f2 | ||
|
|
af0c5c3ccb | ||
|
|
a6e8db99b3 | ||
|
|
e4684752c2 | ||
|
|
4d6269a42d | ||
|
|
593f5ee569 | ||
|
|
4862e22cd0 | ||
|
|
d13a6f7487 | ||
|
|
09066b1ba6 | ||
|
|
8f8f0b3258 | ||
|
|
d9283970a5 | ||
|
|
994afad279 | ||
|
|
b72ea28540 | ||
|
|
fc69c6fac4 | ||
|
|
4100fd2817 | ||
|
|
686744e48e | ||
|
|
0f49221f57 | ||
|
|
725720dfc3 | ||
|
|
96cdb8edb7 | ||
|
|
7aa197be7d | ||
|
|
ea1dbfe961 | ||
|
|
4c73da31ba | ||
|
|
5febae8ad0 | ||
|
|
d06f01a7d7 | ||
|
|
54d757a4c7 | ||
|
|
a23e1cf729 | ||
|
|
91879960e6 | ||
|
|
270e6959b8 | ||
|
|
cbb3ca01f4 | ||
|
|
9845d6fd40 | ||
|
|
e5a59d6925 | ||
|
|
574170488c | ||
|
|
9ea99efe13 | ||
|
|
b3af88708d | ||
|
|
b96ce0b764 | ||
|
|
97ea39404a | ||
|
|
4054f26c4d | ||
|
|
7380731bf7 | ||
|
|
3bea349f9e | ||
|
|
98e0c8d609 | ||
|
|
71f7385fcb | ||
|
|
fbedf0ba6b | ||
|
|
cf710eab13 | ||
|
|
b216a6a30e | ||
|
|
b79086b3e9 | ||
|
|
b551bdb0ce | ||
|
|
0886bc7afd | ||
|
|
e7027e3d40 | ||
|
|
243690b5ab | ||
|
|
5b5f76002e | ||
|
|
fc03f1a1e6 | ||
|
|
1d59ae9aa9 | ||
|
|
8fde1b9f2c | ||
|
|
5e03f8c725 | ||
|
|
d6d4a50f7c | ||
|
|
fe4e1de566 | ||
|
|
e0d34b8f47 | ||
|
|
17c9d35449 | ||
|
|
0e994265c6 | ||
|
|
e16319a290 | ||
|
|
c033643f07 | ||
|
|
607e2248c8 | ||
|
|
a1111c7aa0 | ||
|
|
1b82e70fc1 | ||
|
|
35068c2e6e | ||
|
|
212703edf8 | ||
|
|
7460d1a446 | ||
|
|
c851205f83 | ||
|
|
dd0e073159 | ||
|
|
193b477086 | ||
|
|
3f85da0098 | ||
|
|
dad28f3dfe | ||
|
|
e8e1da3fb5 | ||
|
|
4a24311161 | ||
|
|
4f8c6b7773 | ||
|
|
26fc2c24bd | ||
|
|
330f9daade | ||
|
|
4a232bc868 | ||
|
|
61dff96474 | ||
|
|
bda28bbf38 | ||
|
|
66bedfd8e4 | ||
|
|
c18f968d84 | ||
|
|
5dfbc57117 | ||
|
|
e3fb6771d6 | ||
|
|
f4da3c7f1b | ||
|
|
81dbc9c070 | ||
|
|
431bc87f85 | ||
|
|
b0e224a9f8 | ||
|
|
e3e6e75d40 | ||
|
|
ed856f2ab8 | ||
|
|
6425e1c52f | ||
|
|
c842087cc1 | ||
|
|
2651b381bb | ||
|
|
4143d9871e | ||
|
|
fb9e467147 | ||
|
|
8b959158e3 | ||
|
|
ecb898c7ff | ||
|
|
c2b2b1ab5c | ||
|
|
d4682b3b38 | ||
|
|
2f4a50064f | ||
|
|
6851535fe7 | ||
|
|
292a5f50b2 | ||
|
|
c25ce7c585 | ||
|
|
b22c9a86a9 | ||
|
|
767bb952a5 | ||
|
|
32e7178bbb | ||
|
|
614f671b92 | ||
|
|
af62dbf3d3 | ||
|
|
249e6af3a6 | ||
|
|
59bed375d0 | ||
|
|
aba95b00aa | ||
|
|
011ee5b180 | ||
|
|
4e19719bdd | ||
|
|
fa469aaf41 | ||
|
|
3cabf608ca | ||
|
|
2e841622f8 | ||
|
|
9b5e3797b1 | ||
|
|
07df177332 | ||
|
|
ff364347cf | ||
|
|
4c74ff5e5a | ||
|
|
2ebd19c9bc | ||
|
|
875ffa49b3 | ||
|
|
ff0030d74f | ||
|
|
7a71feed8c | ||
|
|
70c4ce199d | ||
|
|
ed0f8ccbaf | ||
|
|
3e5ca2e168 | ||
|
|
d0dc59e792 | ||
|
|
0106c64369 | ||
|
|
69fdb41934 | ||
|
|
550b3ee1d3 | ||
|
|
961cc6a6d3 | ||
|
|
05091ab656 | ||
|
|
272505b99d | ||
|
|
60a769955b | ||
|
|
34bec53474 | ||
|
|
c77ae65a0d | ||
|
|
1ed0430b82 | ||
|
|
82f640e360 | ||
|
|
44aabc3ae4 | ||
|
|
bbdf9b2745 | ||
|
|
96a87170f7 | ||
|
|
281323db42 | ||
|
|
32258ee8ae | ||
|
|
df0faef9ca | ||
|
|
9c3a020ecf | ||
|
|
4c4cc55bb7 | ||
|
|
f4c2e7e629 | ||
|
|
eadef08fd5 | ||
|
|
0c725a257d | ||
|
|
6f35fb5f80 | ||
|
|
cd1fe75987 | ||
|
|
e92e320956 | ||
|
|
0e4757e0fb | ||
|
|
bd6af68bc5 | ||
|
|
13050f73c1 | ||
|
|
5472fb0c56 | ||
|
|
73c2424b24 | ||
|
|
5117eda688 | ||
|
|
cfbef51d3d | ||
|
|
09cb2d76ef | ||
|
|
3f549ad0df | ||
|
|
60d26be325 | ||
|
|
013d0d3753 | ||
|
|
97da67c6a8 | ||
|
|
f74072ba28 | ||
|
|
19eac239b7 | ||
|
|
31cd41bfe4 | ||
|
|
af6c321395 | ||
|
|
448fca1fdf | ||
|
|
1923928fdc | ||
|
|
bee5574656 | ||
|
|
8c8a68d850 | ||
|
|
9159b5b120 | ||
|
|
2d0079905e | ||
|
|
83c227d53c | ||
|
|
ee57b865b0 | ||
|
|
ecbb9cfa90 | ||
|
|
8545e8496b | ||
|
|
75b2610e85 | ||
|
|
237021ec15 | ||
|
|
4f5c25d0dd | ||
|
|
4c33ab1997 | ||
|
|
5bb65aca8f | ||
|
|
3fd7babacc | ||
|
|
caea8a9588 | ||
|
|
e1d6cba014 | ||
|
|
1f91fe7a2c | ||
|
|
dc53261c3b | ||
|
|
b3e90a93b0 | ||
|
|
1f3e2b770c | ||
|
|
d310e896cb | ||
|
|
a36245cef6 | ||
|
|
092ef90f29 | ||
|
|
64f59ff71e | ||
|
|
a7f80a2770 | ||
|
|
a5c5e3e876 | ||
|
|
8e4fb993c0 | ||
|
|
846567275a | ||
|
|
741c972935 | ||
|
|
6c2760c9cd | ||
|
|
b35a5ee4a3 | ||
|
|
345385376a | ||
|
|
dbe9db26fc | ||
|
|
91ba22b157 | ||
|
|
86b2736480 | ||
|
|
cfe2fb66ab | ||
|
|
428e61253c | ||
|
|
95bcd0c9d5 | ||
|
|
23bada3c5a | ||
|
|
de0cf8433b | ||
|
|
1b49ea4061 | ||
|
|
29b94d6ba3 | ||
|
|
80a435f00b | ||
|
|
fdcd5806b1 | ||
|
|
9ddcfce915 | ||
|
|
6ba358533b | ||
|
|
73aa329d57 | ||
|
|
379016fd78 | ||
|
|
ea4b586c77 | ||
|
|
6961f2caae | ||
|
|
4df2ce4409 | ||
|
|
052a4f432c | ||
|
|
de86ff051e | ||
|
|
f5feeab48d | ||
|
|
1317af028e | ||
|
|
cdcd4ddd35 | ||
|
|
2960164cf8 | ||
|
|
a98ef9787c | ||
|
|
b6d406fbc8 | ||
|
|
e3488292ba | ||
|
|
fea2e0be4f | ||
|
|
751f5dfda3 | ||
|
|
d5f71e66f9 | ||
|
|
03e810ec72 | ||
|
|
6c6f4bcd45 | ||
|
|
304942302b | ||
|
|
8dc1a74df8 | ||
|
|
e295d01505 | ||
|
|
aa1b29ea0e | ||
|
|
cef857fbbd | ||
|
|
6bba8ce0dc | ||
|
|
b0330d62e5 | ||
|
|
fc0c857cfe | ||
|
|
238b18b8ac | ||
|
|
6a2d023b7b | ||
|
|
4bb1fff15d | ||
|
|
37f5bda227 | ||
|
|
56b571fcaa | ||
|
|
46bf3c9e9c | ||
|
|
361fb22954 | ||
|
|
203fe0f4bf | ||
|
|
36ac5fe735 | ||
|
|
7569519530 | ||
|
|
a848179286 | ||
|
|
456ab38caa | ||
|
|
c71b5c0426 | ||
|
|
868cc52415 | ||
|
|
8c168cc337 | ||
|
|
f9fa4cc099 | ||
|
|
a0540cafb3 | ||
|
|
88b3924132 | ||
|
|
3023f26911 | ||
|
|
c9347d3d7d | ||
|
|
d85c7d06af | ||
|
|
e229f79741 | ||
|
|
a4d236eebe | ||
|
|
1192fd27c6 | ||
|
|
cd1cb40033 | ||
|
|
14e085f70e | ||
|
|
fc37d81144 | ||
|
|
a859455aad | ||
|
|
93d596ace2 | ||
|
|
c03e3fe88a | ||
|
|
a90a5c9244 | ||
|
|
26772f8184 | ||
|
|
8f8ad83861 | ||
|
|
d111b42cf1 | ||
|
|
821c965b45 | ||
|
|
4acac9a294 | ||
|
|
4adb06ae91 | ||
|
|
dce7a1e2aa | ||
|
|
a354b72546 | ||
|
|
ac8f41404b | ||
|
|
fc7b257bab | ||
|
|
787066c292 | ||
|
|
71ab6cb818 | ||
|
|
1158ba453e | ||
|
|
2e3f764272 | ||
|
|
2172f1d2cd | ||
|
|
6efc1eae9f | ||
|
|
6a740033de | ||
|
|
d754598143 | ||
|
|
47f632263e | ||
|
|
98af0b0c77 | ||
|
|
b9c6a62437 | ||
|
|
57670eeeb7 | ||
|
|
f26ee11913 | ||
|
|
2435d76a39 | ||
|
|
348d460ab7 | ||
|
|
2b8b43b3db | ||
|
|
91b74b6896 | ||
|
|
319fd19b5e | ||
|
|
4edd796509 | ||
|
|
b0ced1bd2c | ||
|
|
6ed3a7774f | ||
|
|
1ce3feb893 | ||
|
|
ebbc5eceb8 | ||
|
|
0cac4a4e0c | ||
|
|
1908403324 | ||
|
|
faa07b71f9 | ||
|
|
e9dcf6b8dd | ||
|
|
3ea60ea0ae | ||
|
|
54171dfdd3 | ||
|
|
dc8db34155 | ||
|
|
a68f3939cf | ||
|
|
ae90497762 | ||
|
|
2b55f6420a | ||
|
|
6d3545624d | ||
|
|
46dc5beee9 | ||
|
|
943cc16020 | ||
|
|
a6f5ce8c7b | ||
|
|
bc3d0feb5c | ||
|
|
580f0f1a28 | ||
|
|
715b0c9b6c | ||
|
|
388afa07f4 | ||
|
|
1def60cd2c | ||
|
|
cdb4816fbb | ||
|
|
be46588cf0 | ||
|
|
6dc2f7231b | ||
|
|
3165b77ec9 | ||
|
|
ad0e2b86dc | ||
|
|
5ee0b01118 | ||
|
|
fbfd0c7353 | ||
|
|
ee8970c11e | ||
|
|
82a1f33260 | ||
|
|
9607b322d2 | ||
|
|
238c74643b | ||
|
|
712c1783b6 | ||
|
|
081fb6ec78 | ||
|
|
c04d332b7f | ||
|
|
32786acf19 | ||
|
|
51dd2762a9 | ||
|
|
cf31bdb65c | ||
|
|
50cae84100 | ||
|
|
98feca280f | ||
|
|
304c4e3d3b | ||
|
|
c5b55049b9 | ||
|
|
c494eb94f4 | ||
|
|
5f173e9357 | ||
|
|
307a7ad077 | ||
|
|
0039834bb9 | ||
|
|
d064c625f4 | ||
|
|
77a62b8594 | ||
|
|
d4339661df | ||
|
|
39a014f601 | ||
|
|
1e22160e74 | ||
|
|
267bf01259 | ||
|
|
e23fa65ef2 | ||
|
|
ee7ff024c1 | ||
|
|
e8a92b67c3 | ||
|
|
3ce7489531 | ||
|
|
ffbb35fa01 | ||
|
|
de0b69691d | ||
|
|
82aae20e9c | ||
|
|
7362b14d41 | ||
|
|
77d7babf92 | ||
|
|
545b347ca5 | ||
|
|
df2111eb4f | ||
|
|
c7d3b7438c | ||
|
|
5c0ad86f19 | ||
|
|
675cf7ef59 | ||
|
|
d74e7fc084 | ||
|
|
2cd85ddf11 | ||
|
|
3c1dc9cfaa | ||
|
|
8b2553b3f4 | ||
|
|
b9373700a2 | ||
|
|
bdce4b84d8 | ||
|
|
2dd4609699 | ||
|
|
5c67ca015b | ||
|
|
957b329e94 | ||
|
|
120ebea917 | ||
|
|
6e1e11f6cd | ||
|
|
dbc056f9ac | ||
|
|
7de815e957 | ||
|
|
1894d6e6ff | ||
|
|
1cc722d0cc | ||
|
|
ec07927b55 | ||
|
|
41c7e4fe87 | ||
|
|
217cd0f5e9 | ||
|
|
fd02dca60e | ||
|
|
2a1d58ed22 | ||
|
|
7d8003da46 | ||
|
|
03edcd2bfd | ||
|
|
a9d3f48372 | ||
|
|
316ec5b398 | ||
|
|
d06defd885 | ||
|
|
0fed68dd16 | ||
|
|
ce60fe04cb | ||
|
|
4e1c62d7f1 | ||
|
|
3ea8e01a9d | ||
|
|
9cbd36163c | ||
|
|
0f5c3e107e | ||
|
|
1ae251ea5b | ||
|
|
90742541c6 | ||
|
|
84d8dfd46c | ||
|
|
3ed404e5bb | ||
|
|
4b64ffc365 | ||
|
|
e297cc4c2a | ||
|
|
9ab63c58f2 | ||
|
|
3c0aceb9f7 | ||
|
|
d7bd3d2d69 | ||
|
|
3136226134 | ||
|
|
5a7535c513 | ||
|
|
991ab5de64 | ||
|
|
b17e4fa3bf | ||
|
|
35fa5b7dfc | ||
|
|
7812214db6 | ||
|
|
a5a8467993 | ||
|
|
544ea7ccfc | ||
|
|
024b5310fa | ||
|
|
177cb8bbe1 | ||
|
|
35f137df35 | ||
|
|
c71ee7a3e6 | ||
|
|
9a2dbb26a5 | ||
|
|
3d2fd06035 | ||
|
|
2f6d0c006c | ||
|
|
43088ee8ba | ||
|
|
c17b6e7be3 | ||
|
|
71299633d5 | ||
|
|
dfe61cbe9c | ||
|
|
18c9210342 | ||
|
|
1167e6b86f | ||
|
|
1684fa8c63 | ||
|
|
b4dce61918 | ||
|
|
d7ddcc0768 | ||
|
|
36c26b6903 | ||
|
|
2300c692b8 | ||
|
|
da6dbbd433 | ||
|
|
0a4bd8cb7d | ||
|
|
32d357e1a8 | ||
|
|
21e259d1a4 | ||
|
|
c3a54aa59a | ||
|
|
7713df9e41 | ||
|
|
49900b79a9 | ||
|
|
4f075a1aef | ||
|
|
d4cd902e1c | ||
|
|
ef4484ab27 | ||
|
|
9e7f9f3471 | ||
|
|
493e8580d6 | ||
|
|
bce567db46 | ||
|
|
38e2c8cb8a | ||
|
|
16309544ac | ||
|
|
517b5da67a | ||
|
|
98460af44f | ||
|
|
7213d5a76b | ||
|
|
bb29c5b322 | ||
|
|
58ad7bae48 | ||
|
|
82a3480b12 | ||
|
|
c00811a846 | ||
|
|
27eaf46c8a | ||
|
|
202aeece3c | ||
|
|
825fc895dc | ||
|
|
a74aecedf1 | ||
|
|
fa1f63bcd0 | ||
|
|
c2bce3e93e | ||
|
|
a46733e701 | ||
|
|
8f350f9b9f | ||
|
|
484692aacd | ||
|
|
7f0df99511 | ||
|
|
bebd2fe7e7 | ||
|
|
36e8839675 | ||
|
|
61305a50c1 | ||
|
|
1d7749a40f | ||
|
|
f01d044618 | ||
|
|
31532adf86 | ||
|
|
879e06db39 | ||
|
|
4beb0f702a | ||
|
|
a771460dbd | ||
|
|
f849f83d84 | ||
|
|
1d084a41ad | ||
|
|
c4198986f1 | ||
|
|
7514786b20 | ||
|
|
9df042c0b8 | ||
|
|
37e0150f70 | ||
|
|
294e4cbcb7 | ||
|
|
952716afe1 | ||
|
|
24aba9a514 | ||
|
|
905993751c | ||
|
|
0b10d877b0 | ||
|
|
874fa5810d | ||
|
|
5be31bbce6 | ||
|
|
a6e3a31690 | ||
|
|
506f3f7b57 | ||
|
|
cd1c36ef94 | ||
|
|
ee689d88b4 | ||
|
|
b93b676336 | ||
|
|
1c6d66fccc | ||
|
|
114356ad2e | ||
|
|
7ab419701c | ||
|
|
d41b1a7560 | ||
|
|
622943529e | ||
|
|
9d7cc152f9 | ||
|
|
3f73d448f3 | ||
|
|
a1b606803f | ||
|
|
b2c7b40568 | ||
|
|
0cbe09d43a | ||
|
|
f1d5b94762 | ||
|
|
6fc2e7c774 | ||
|
|
3b39c1d1ef | ||
|
|
5a3e4abf71 | ||
|
|
48e9362186 | ||
|
|
03a74b74e5 | ||
|
|
248f99cad3 | ||
|
|
d2f0773eb8 | ||
|
|
dd36d56d47 | ||
|
|
0270fc66a1 | ||
|
|
69a844c654 | ||
|
|
5b5a64361f | ||
|
|
26f6d1cb10 | ||
|
|
f87eb1668a | ||
|
|
3114abfd55 | ||
|
|
5a94cff91e | ||
|
|
d704e87ee4 | ||
|
|
c8ce996872 | ||
|
|
0e7b068061 | ||
|
|
71dd149ca2 | ||
|
|
b30ba41d6a | ||
|
|
a0bf790892 | ||
|
|
caefc4eb8e | ||
|
|
31364c17d6 | ||
|
|
5e56966e72 | ||
|
|
1f951ed7ec | ||
|
|
ecd82f1fc9 | ||
|
|
7aaf1eeb1b | ||
|
|
e53fe70668 | ||
|
|
9e2e0a4a2d | ||
|
|
b52719fd73 | ||
|
|
7953976d25 | ||
|
|
39d6b94835 | ||
|
|
4fdce0695d | ||
|
|
ae8247fe6a | ||
|
|
d664565174 | ||
|
|
b24a46ad8f | ||
|
|
6bffe34faa | ||
|
|
abe3fb4acb | ||
|
|
39905bd8fd | ||
|
|
078dbfb0a9 | ||
|
|
dfeb5cfdd2 | ||
|
|
c1777cfb89 | ||
|
|
974072bdae | ||
|
|
b95e18956f | ||
|
|
3c1c5ef281 | ||
|
|
7194b14cd2 | ||
|
|
4e6f8d561c | ||
|
|
ac26921569 | ||
|
|
a60543728b | ||
|
|
f35ec9771e | ||
|
|
de4fe99e34 | ||
|
|
8ea6b3eebd | ||
|
|
a01836fe8d | ||
|
|
268dc97857 | ||
|
|
fc203c9654 | ||
|
|
8eedd5b277 | ||
|
|
561d9ac2bc | ||
|
|
1112da76f1 | ||
|
|
081aa18f39 | ||
|
|
c05c8bbba1 | ||
|
|
eabd23f31e | ||
|
|
cc27088df9 | ||
|
|
97ab7e9c65 | ||
|
|
bbf92828f6 | ||
|
|
2f83bf9f83 | ||
|
|
b2a1728201 | ||
|
|
18cbbbe9aa | ||
|
|
d90f8a3697 | ||
|
|
fe3ef6fc2e | ||
|
|
1b9148f12f | ||
|
|
deb8e49483 | ||
|
|
d75af2a156 | ||
|
|
9895edefff | ||
|
|
b60e856087 | ||
|
|
6244b4d00f | ||
|
|
ee167b1a43 | ||
|
|
e8b9bfe44c | ||
|
|
50f5593ffc | ||
|
|
3f0f7acbc0 | ||
|
|
7f6f8ec386 | ||
|
|
24d1798779 | ||
|
|
3e9d603f0b | ||
|
|
71a8fd3106 | ||
|
|
49279a3c19 | ||
|
|
43a1291f7c | ||
|
|
6dc5340f60 | ||
|
|
2a6e33bc73 | ||
|
|
0f6b2cfd3d | ||
|
|
30d109c0e9 | ||
|
|
e8e1f844d9 | ||
|
|
05a89e5566 | ||
|
|
c122889c95 | ||
|
|
9de5dc932b | ||
|
|
289c9ecf5d | ||
|
|
2c1a6e3f94 | ||
|
|
ad092a898d | ||
|
|
56f2548b6e | ||
|
|
25467243a6 | ||
|
|
e07d40fc26 | ||
|
|
09877e4e63 | ||
|
|
d3460b6cf5 | ||
|
|
ba384d15d2 | ||
|
|
2f38ade0e0 | ||
|
|
4d110d4c82 | ||
|
|
1bf5ff3e6e | ||
|
|
cd2a1a169f | ||
|
|
59b5f360af | ||
|
|
e8b6890318 | ||
|
|
d7b9ed05f0 | ||
|
|
dc852a100f | ||
|
|
838d51d296 | ||
|
|
e2845bc032 | ||
|
|
8c021fd784 | ||
|
|
406ec14585 | ||
|
|
c27b42e425 | ||
|
|
2d94d7ab0c | ||
|
|
5fcf430c81 | ||
|
|
cea4b3e363 | ||
|
|
e00d8fb544 | ||
|
|
e654fabe04 | ||
|
|
18592a08be | ||
|
|
1763260578 | ||
|
|
955f10e621 | ||
|
|
2565fedeb7 | ||
|
|
6b8e553ecc | ||
|
|
14f81cb275 | ||
|
|
ddb844226d | ||
|
|
f87ee5112a | ||
|
|
2a1a773777 | ||
|
|
7fede3ee45 | ||
|
|
abcd3511bf | ||
|
|
a387557970 | ||
|
|
daba04d54b | ||
|
|
b00a87d8fa | ||
|
|
aee55b0595 | ||
|
|
e58883c183 | ||
|
|
321e840c1c | ||
|
|
19ac1dd393 | ||
|
|
13796ee4c7 | ||
|
|
10bb78458d | ||
|
|
6997506bb9 | ||
|
|
480c7178a8 | ||
|
|
0279d8f466 | ||
|
|
1a6183d0c4 | ||
|
|
487acbb573 | ||
|
|
f97eba6539 | ||
|
|
cac84abdd9 | ||
|
|
ef045f9f65 | ||
|
|
6002099288 | ||
|
|
181f621a90 | ||
|
|
5a71c6f2eb | ||
|
|
487965dc8a | ||
|
|
874c573bd4 | ||
|
|
f63e1cfbfc | ||
|
|
f049f719f8 | ||
|
|
30754473fc | ||
|
|
7c70e6ce74 | ||
|
|
a702b7ccc5 | ||
|
|
f6be62ac5f | ||
|
|
dddd30bef8 | ||
|
|
a054206d25 | ||
|
|
5b6f06b2ac | ||
|
|
6f83822b6e | ||
|
|
9b635a3e90 | ||
|
|
172af5465d | ||
|
|
22f10dd8d2 | ||
|
|
790fdc0aa6 | ||
|
|
45356f5e12 | ||
|
|
08ee50403d | ||
|
|
aa1551c6e8 | ||
|
|
879403a172 | ||
|
|
6ddf765d8d | ||
|
|
38d83c27b4 | ||
|
|
103fa8fa2c | ||
|
|
53dcee6176 | ||
|
|
0c6129c54e | ||
|
|
1f01754ea6 | ||
|
|
f8a7ab1752 | ||
|
|
09842ce46f | ||
|
|
0b849985b2 | ||
|
|
34b8a48252 | ||
|
|
6f6e1efbc8 | ||
|
|
9a72ec366d | ||
|
|
d97302f351 | ||
|
|
4eb75f3c80 | ||
|
|
e5f72a0d4f | ||
|
|
b11b11f9b0 | ||
|
|
70077db07d | ||
|
|
eed682c529 | ||
|
|
fbf2d64f34 | ||
|
|
48bf08922c | ||
|
|
3616ee50c0 | ||
|
|
255c8e8ff4 | ||
|
|
0891e84bf8 | ||
|
|
a63db4ab24 | ||
|
|
169d45fbdb | ||
|
|
965e0237a3 | ||
|
|
4caef0dec7 | ||
|
|
622763b240 | ||
|
|
35d29b22c0 | ||
|
|
fee1d659cf | ||
|
|
869767a5cf | ||
|
|
23b01621ff | ||
|
|
f21ebaf839 | ||
|
|
f6f00b98a7 | ||
|
|
187170ec51 | ||
|
|
f7ad64a3d3 | ||
|
|
103d75f773 | ||
|
|
ed2968e3e8 | ||
|
|
fef5121cee | ||
|
|
c84983f91e | ||
|
|
86f4f4440a | ||
|
|
af0887fb48 | ||
|
|
610c7858d6 | ||
|
|
8d1fb88a20 | ||
|
|
1e2ad19d68 | ||
|
|
7bee66fe36 | ||
|
|
303fe886b7 | ||
|
|
761a472b45 | ||
|
|
3cf2da877f | ||
|
|
5b7b1596a2 | ||
|
|
dc58985ac6 | ||
|
|
5e0db46f17 | ||
|
|
4e19bc01d5 | ||
|
|
2d2acda404 | ||
|
|
fa8d5d1769 | ||
|
|
fe058e2c27 | ||
|
|
a22a24bc98 | ||
|
|
b7c2465887 | ||
|
|
f34158250a | ||
|
|
87dcc9fe07 | ||
|
|
c56e0eb556 | ||
|
|
ba959970c6 | ||
|
|
c75e31d3da | ||
|
|
bcc2330a18 | ||
|
|
f0f5913efe | ||
|
|
17aefd333a | ||
|
|
b86a652b90 | ||
|
|
5968323642 | ||
|
|
26727882d0 | ||
|
|
106e441a61 | ||
|
|
6d22ba9f87 | ||
|
|
8cd9db272f | ||
|
|
b8691649c5 | ||
|
|
e9a2938c6b | ||
|
|
44fa0bfbc6 | ||
|
|
36c213ed3a | ||
|
|
5f26f8a03d | ||
|
|
471f781022 | ||
|
|
f6cb8e4118 | ||
|
|
515eff269c | ||
|
|
bd370ab789 | ||
|
|
3e10116437 | ||
|
|
05f665ecda | ||
|
|
cd65f6a84d | ||
|
|
6d2979459e | ||
|
|
dee38e9c0b | ||
|
|
b4fc36ea62 | ||
|
|
fb6b4739e4 | ||
|
|
32700cc51b | ||
|
|
1ac353d24e | ||
|
|
d7686201dc | ||
|
|
248733de44 | ||
|
|
e410ba9623 | ||
|
|
8295bde95a | ||
|
|
f3a9e95dd8 | ||
|
|
7378e3be01 | ||
|
|
1968efe9f0 | ||
|
|
2b6808f165 | ||
|
|
92f14d28d1 | ||
|
|
954214e48c | ||
|
|
828e6f2077 | ||
|
|
982b7373ea | ||
|
|
39b5359efd | ||
|
|
627a538bf2 | ||
|
|
e07e3ecc22 | ||
|
|
b426db6086 | ||
|
|
d4b43d8578 | ||
|
|
b9b1680f08 | ||
|
|
3e37975a00 | ||
|
|
b0e252684d | ||
|
|
919e1c3f08 | ||
|
|
16dc58312c | ||
|
|
169bd9db5e | ||
|
|
4e5e8fd8fe | ||
|
|
8728ba08e2 | ||
|
|
3ba07ed27f | ||
|
|
9b4b659804 | ||
|
|
c00a31077c | ||
|
|
e8fc17f816 | ||
|
|
4a2da4b51e | ||
|
|
180d96234e | ||
|
|
1a04ffbae4 | ||
|
|
1fe014dbae | ||
|
|
579c31aa23 | ||
|
|
74c914475f | ||
|
|
1ca439f4e0 | ||
|
|
08e7c143b3 | ||
|
|
d399dfa792 | ||
|
|
f6e613a76f | ||
|
|
c6a8b6471a | ||
|
|
83589b7cec | ||
|
|
aeea93fa95 | ||
|
|
be417d6605 | ||
|
|
2f890dea18 | ||
|
|
de76628539 | ||
|
|
598dd672bc | ||
|
|
d12fb3d6e1 | ||
|
|
9504d866b6 | ||
|
|
865b1dc66e | ||
|
|
5143b210cf | ||
|
|
f34ce81f25 | ||
|
|
b072c6c4c9 | ||
|
|
7951ed3bce | ||
|
|
02431c57db | ||
|
|
3f186c009c | ||
|
|
6f4c15b2b2 | ||
|
|
b31e029000 | ||
|
|
5f5ffcd48a | ||
|
|
cc76f3746f | ||
|
|
982da4d20c | ||
|
|
113374fd04 | ||
|
|
e4520693dd | ||
|
|
ccffc88ceb | ||
|
|
7c9312607c | ||
|
|
286c2960c8 | ||
|
|
a12e374a04 | ||
|
|
d799c8bd1e | ||
|
|
251eec8401 | ||
|
|
bca8a32674 | ||
|
|
c740324636 | ||
|
|
f049afcb5b | ||
|
|
c188654ebd | ||
|
|
a6aba8cab2 | ||
|
|
583fbfdb2a | ||
|
|
7c34ac6f6d | ||
|
|
b72354ca22 | ||
|
|
82d81b9e86 | ||
|
|
ed19ddf620 | ||
|
|
ebbd33db7a | ||
|
|
7ba4ca1854 | ||
|
|
fa1f8c0d87 | ||
|
|
e0cacef52e | ||
|
|
767ed40b75 | ||
|
|
3c2f92a7af | ||
|
|
2568f828c8 | ||
|
|
5427f55358 | ||
|
|
92b41e4935 | ||
|
|
6edae6ddef | ||
|
|
f787eafd8a | ||
|
|
9588a961d6 | ||
|
|
88758703fa | ||
|
|
3c839f44d8 | ||
|
|
304bdd7d0d | ||
|
|
382d27b4dc | ||
|
|
b80278c04f | ||
|
|
7d4fcfa191 | ||
|
|
ad3fe00dea | ||
|
|
f507d16baa | ||
|
|
dcce2edc4f | ||
|
|
e7e1e7a0a3 | ||
|
|
68f4485cdd | ||
|
|
d93ac3c496 | ||
|
|
a97de38b6b | ||
|
|
444eac3597 | ||
|
|
1f01c76fa5 |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -6,10 +6,12 @@ Makefile.in.in
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
**/*.dirstamp
|
||||
.deps/
|
||||
.libs/
|
||||
src/cryptsetup
|
||||
src/veritysetup
|
||||
ABOUT-NLS
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
@@ -21,8 +23,11 @@ config.rpath
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
cryptsetup
|
||||
cryptsetup-reencrypt
|
||||
depcomp
|
||||
install-sh
|
||||
integritysetup
|
||||
lib/libcryptsetup.pc
|
||||
libtool
|
||||
ltmain.sh
|
||||
@@ -31,10 +36,20 @@ missing
|
||||
po/Makevars.template
|
||||
po/POTFILES
|
||||
po/Rules-quot
|
||||
po/*.pot
|
||||
po/*.header
|
||||
po/*.sed
|
||||
po/*.sin
|
||||
po/stamp-po
|
||||
scripts/cryptsetup.conf
|
||||
stamp-h1
|
||||
|
||||
veritysetup
|
||||
tests/valglog.*
|
||||
*/*.dirstamp
|
||||
*-debug-luks2-backup*
|
||||
tests/api-test
|
||||
tests/api-test-2
|
||||
tests/differ
|
||||
tests/luks1-images
|
||||
tests/tcrypt-images
|
||||
tests/unit-utils-io
|
||||
tests/vectors-test
|
||||
|
||||
15
.gitlab/issue_templates/Bug.md
Normal file
15
.gitlab/issue_templates/Bug.md
Normal file
@@ -0,0 +1,15 @@
|
||||
### Issue description
|
||||
<!-- Please, shortly describe the issue here. -->
|
||||
|
||||
### Steps for reproducing the issue
|
||||
<!-- How it can be reproduced? Include all important steps. -->
|
||||
|
||||
### Additional info
|
||||
<!-- Please mention what distribution you are using. -->
|
||||
|
||||
### Debug log
|
||||
<!-- Paste a debug log of the failing command (add --debug option) between the markers below (to keep raw debug format).-->
|
||||
```
|
||||
Output with --debug option:
|
||||
|
||||
```
|
||||
5
.gitlab/issue_templates/Documentation.md
Normal file
5
.gitlab/issue_templates/Documentation.md
Normal file
@@ -0,0 +1,5 @@
|
||||
### Documentation issue
|
||||
<!-- Please, shortly describe the issue in documentation here. -->
|
||||
|
||||
### Additional info
|
||||
<!-- Please mention what cryptsetup version you are using. -->
|
||||
5
.gitlab/issue_templates/Feature.md
Normal file
5
.gitlab/issue_templates/Feature.md
Normal file
@@ -0,0 +1,5 @@
|
||||
### New feature description
|
||||
<!-- Please, shortly describe the requested feature here. -->
|
||||
|
||||
### Additional info
|
||||
<!-- Please mention what distribution and cryptsetup version you are using. -->
|
||||
@@ -36,23 +36,14 @@ function check_nonroot
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
sudo modprobe dm-crypt
|
||||
sudo modprobe dm-verity
|
||||
sudo modprobe dm-integrity
|
||||
uname -a
|
||||
sudo dmsetup version
|
||||
sudo dmsetup targets
|
||||
|
||||
make check || return
|
||||
|
||||
#sudo $MAKE install || return
|
||||
make check
|
||||
}
|
||||
|
||||
function check_root
|
||||
@@ -62,24 +53,15 @@ function check_root
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
sudo modprobe dm-crypt
|
||||
sudo modprobe dm-verity
|
||||
sudo modprobe dm-integrity
|
||||
uname -a
|
||||
sudo dmsetup version
|
||||
sudo dmsetup targets
|
||||
|
||||
# FIXME: we should use -E option here
|
||||
sudo make check || return
|
||||
|
||||
#sudo $MAKE install || return
|
||||
sudo make check
|
||||
}
|
||||
|
||||
function check_nonroot_compile_only
|
||||
@@ -89,8 +71,8 @@ function check_nonroot_compile_only
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
@@ -102,7 +84,6 @@ function travis_install_script
|
||||
# install some packages from Ubuntu's default sources
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -qq >/dev/null \
|
||||
python-dev \
|
||||
sharutils \
|
||||
libgcrypt20-dev \
|
||||
libssl-dev \
|
||||
@@ -120,6 +101,7 @@ function travis_install_script
|
||||
expect \
|
||||
keyutils \
|
||||
libjson-c-dev \
|
||||
libblkid-dev \
|
||||
|| return
|
||||
}
|
||||
|
||||
@@ -141,19 +123,26 @@ function travis_script
|
||||
|
||||
case "$MAKE_CHECK" in
|
||||
gcrypt)
|
||||
check_nonroot "--with-crypto_backend=gcrypt"
|
||||
check_nonroot "--with-crypto_backend=gcrypt" && \
|
||||
check_root "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
gcrypt_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
openssl)
|
||||
check_nonroot "--with-crypto_backend=openssl"
|
||||
check_nonroot "--with-crypto_backend=openssl" && \
|
||||
check_root "--with-crypto_backend=openssl"
|
||||
;;
|
||||
openssl_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=openssl"
|
||||
;;
|
||||
kernel)
|
||||
check_nonroot "--with-crypto_backend=kernel" && \
|
||||
check_root "--with-crypto_backend=kernel"
|
||||
;;
|
||||
kernel_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=kernel"
|
||||
;;
|
||||
*)
|
||||
echo "error, check environment (travis.yml)" >&2
|
||||
false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
language: c
|
||||
|
||||
sudo: required
|
||||
dist: trusty
|
||||
dist: bionic
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
@@ -9,6 +9,7 @@ compiler:
|
||||
env:
|
||||
- MAKE_CHECK="gcrypt"
|
||||
- MAKE_CHECK="openssl"
|
||||
- MAKE_CHECK="kernel"
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
||||
1
AUTHORS
1
AUTHORS
@@ -1,3 +1,4 @@
|
||||
Jana Saout <jana@saout.de>
|
||||
Clemens Fruhwirth <clemens@endorphin.org>
|
||||
Milan Broz <gmazyland@gmail.com>
|
||||
Ondrej Kozina <okozina@redhat.com>
|
||||
|
||||
2
INSTALL
2
INSTALL
@@ -44,7 +44,7 @@ The simplest way to compile this package is:
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
Running `configure' takes a while. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
13
Makefile.am
13
Makefile.am
@@ -1,6 +1,5 @@
|
||||
EXTRA_DIST = COPYING.LGPL FAQ docs misc
|
||||
SUBDIRS = po tests
|
||||
TESTS =
|
||||
CLEANFILES =
|
||||
DISTCLEAN_TARGETS =
|
||||
|
||||
@@ -16,6 +15,8 @@ AM_CPPFLAGS = \
|
||||
AM_CFLAGS = -Wall
|
||||
AM_LDFLAGS =
|
||||
|
||||
LDADD = $(LTLIBINTL) -lm
|
||||
|
||||
tmpfilesddir = @DEFAULT_TMPFILESDIR@
|
||||
|
||||
noinst_LTLIBRARIES =
|
||||
@@ -25,11 +26,11 @@ tmpfilesd_DATA =
|
||||
|
||||
include man/Makemodule.am
|
||||
|
||||
include python/Makemodule.am
|
||||
|
||||
include scripts/Makemodule.am
|
||||
|
||||
if CRYPTO_INTERNAL_ARGON2
|
||||
include lib/crypto_backend/argon2/Makemodule.am
|
||||
endif
|
||||
include lib/crypto_backend/Makemodule.am
|
||||
include lib/Makemodule.am
|
||||
|
||||
@@ -38,12 +39,12 @@ include src/Makemodule.am
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-python \
|
||||
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d
|
||||
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
|
||||
--enable-internal-argon2 --enable-internal-sse-argon2
|
||||
|
||||
distclean-local:
|
||||
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
|
||||
rm -rf autom4te.cache
|
||||
|
||||
clean-local:
|
||||
-rm -rf docs/doxygen_api_docs
|
||||
-rm -rf docs/doxygen_api_docs libargon2.la
|
||||
|
||||
67
README.md
67
README.md
@@ -2,13 +2,13 @@
|
||||
|
||||
What the ...?
|
||||
=============
|
||||
**Cryptsetup** is utility used to conveniently setup disk encryption based
|
||||
on [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
**Cryptsetup** is a utility used to conveniently set up disk encryption based
|
||||
on the [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
|
||||
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**
|
||||
and **TrueCrypt** (including **VeraCrypt** extension) format.
|
||||
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**,
|
||||
**TrueCrypt** (including **VeraCrypt** extension) and **BitLocker** formats.
|
||||
|
||||
Project also includes **veritysetup** utility used to conveniently setup
|
||||
The project also includes a **veritysetup** utility used to conveniently setup
|
||||
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module
|
||||
and, since version 2.0, **integritysetup** to setup
|
||||
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
|
||||
@@ -18,15 +18,17 @@ LUKS Design
|
||||
-----------
|
||||
**LUKS** is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not
|
||||
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
|
||||
In contrast to existing solution, LUKS stores all setup necessary setup information in the partition header,
|
||||
enabling the user to transport or migrate his data seamlessly.
|
||||
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
|
||||
|
||||
Last version of the LUKS format specification is
|
||||
Last version of the LUKS2 format specification is
|
||||
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
|
||||
|
||||
Last version of the LUKS1 format specification is
|
||||
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
|
||||
|
||||
Why LUKS?
|
||||
---------
|
||||
* compatiblity via standardization,
|
||||
* compatibility via standardization,
|
||||
* secure against low entropy attacks,
|
||||
* support for multiple keys,
|
||||
* effective passphrase revocation,
|
||||
@@ -42,43 +44,34 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**The latest cryptsetup TESTING version is 2.0.0-rc1**
|
||||
* [cryptsetup-2.0.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.xz)
|
||||
* Signature [cryptsetup-2.0.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.sign)
|
||||
**The latest stable cryptsetup version is 2.3.1**
|
||||
* [cryptsetup-2.3.1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.1.tar.xz)
|
||||
* Signature [cryptsetup-2.3.1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.1.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.0.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-rc1-ReleaseNotes).
|
||||
|
||||
**The latest cryptsetup version is 1.7.5**
|
||||
* [cryptsetup-1.7.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz)
|
||||
* Signature [cryptsetup-1.7.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 1.7.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
|
||||
* [Cryptsetup 2.3.1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.1-ReleaseNotes).
|
||||
|
||||
Previous versions
|
||||
* [Version 1.7.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.4-ReleaseNotes).
|
||||
* [Version 1.7.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.3-ReleaseNotes).
|
||||
* [Version 1.7.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.2-ReleaseNotes).
|
||||
* [Version 1.7.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.1-ReleaseNotes).
|
||||
* [Version 1.7.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.0-ReleaseNotes).
|
||||
* [Version 2.3.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.0.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.0.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.0-ReleaseNotes).
|
||||
* [Version 2.2.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.2-ReleaseNotes).
|
||||
* [Version 2.0.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
|
||||
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
|
||||
|
||||
Source and API docs
|
||||
-------------------
|
||||
For development version code, please refer to [source](https://gitlab.com/cryptsetup/cryptsetup/tree/master) page,
|
||||
mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.git/) or [GitHub](https://github.com/mbroz/cryptsetup).
|
||||
|
||||
For libcryptsetup documentation see [libcryptsetup API](https://gitlab.com/cryptsetup/cryptsetup/wikis/API/index.html) page.
|
||||
For libcryptsetup documentation see [libcryptsetup API](https://mbroz.fedorapeople.org/libcryptsetup_API/) page.
|
||||
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://gitlab.com/cryptsetup/cryptsetup/wikis/ABI-tracker/timeline/libcryptsetup/index.html).
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
|
||||
|
||||
NLS PO files are maintained by [TranslationProject](http://translationproject.org/domain/cryptsetup.html).
|
||||
|
||||
@@ -90,4 +83,4 @@ For cryptsetup and LUKS related questions, please use the dm-crypt mailing list,
|
||||
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
|
||||
|
||||
You can also browse [list archive](http://www.saout.de/pipermail/dm-crypt/) or read it through
|
||||
[web interface](http://news.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt).
|
||||
[web interface](https://marc.info/?l=dm-crypt).
|
||||
|
||||
6
TODO
6
TODO
@@ -1,5 +1 @@
|
||||
- Support K/M suffixes for align payload (new switch?).
|
||||
- Do we need crypt_data_path() - path to data device (if differs)?
|
||||
- Resync ETA time is not accurate, calculate it better (last minute window?).
|
||||
- Fix all crazy automake warnings (or switch to Cmake).
|
||||
- Nettle3 backend is not compatible
|
||||
Please see issues tracked at https://gitlab.com/cryptsetup/cryptsetup/issues.
|
||||
|
||||
303
configure.ac
303
configure.ac
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.0.0-rc1])
|
||||
AC_INIT([cryptsetup],[2.3.2])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=12:0:0
|
||||
LIBCRYPTSETUP_VERSION_INFO=18:0:6
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
@@ -33,6 +33,7 @@ AC_PROG_MAKE_SET
|
||||
AC_ENABLE_STATIC(no)
|
||||
LT_INIT
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AM_ICONV
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl define PKG_CHECK_VAR for old pkg-config <= 0.28
|
||||
@@ -59,11 +60,19 @@ AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
|
||||
sys/sysmacros.h sys/statvfs.h ctype.h unistd.h locale.h byteswap.h endian.h stdint.h)
|
||||
AC_CHECK_DECLS([O_CLOEXEC],,[AC_DEFINE([O_CLOEXEC],[0], [Defined to 0 if not provided])],
|
||||
[[
|
||||
#ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
]])
|
||||
|
||||
AC_CHECK_HEADERS(uuid/uuid.h,,[AC_MSG_ERROR([You need the uuid library.])])
|
||||
AC_CHECK_HEADER(libdevmapper.h,,[AC_MSG_ERROR([You need the device-mapper library.])])
|
||||
|
||||
AC_ARG_ENABLE(keyring, AS_HELP_STRING([--disable-keyring],[disable kernel keyring support and builtin kernel keyring token]),[], [enable_keyring=yes])
|
||||
AC_ARG_ENABLE([keyring],
|
||||
AS_HELP_STRING([--disable-keyring], [disable kernel keyring support and builtin kernel keyring token]),
|
||||
[], [enable_keyring=yes])
|
||||
if test "x$enable_keyring" = "xyes"; then
|
||||
AC_CHECK_HEADERS(linux/keyctl.h,,[AC_MSG_ERROR([You need Linux kernel headers with kernel keyring service compiled.])])
|
||||
|
||||
@@ -84,7 +93,7 @@ if test "x$enable_keyring" = "xyes"; then
|
||||
|
||||
AC_DEFINE(KERNEL_KEYRING, 1, [Enable kernel keyring service support])
|
||||
fi
|
||||
AM_CONDITIONAL(KERNEL_KEYRING, test x$enable_keyring = xyes)
|
||||
AM_CONDITIONAL(KERNEL_KEYRING, test "x$enable_keyring" = "xyes")
|
||||
|
||||
saved_LIBS=$LIBS
|
||||
AC_CHECK_LIB(uuid, uuid_clear, ,[AC_MSG_ERROR([You need the uuid library.])])
|
||||
@@ -92,9 +101,9 @@ AC_SUBST(UUID_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
|
||||
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate])
|
||||
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate explicit_bzero])
|
||||
|
||||
if test "x$enable_largefile" = "xno" ; then
|
||||
if test "x$enable_largefile" = "xno"; then
|
||||
AC_MSG_ERROR([Building with --disable-largefile is not supported, it can cause data corruption.])
|
||||
fi
|
||||
|
||||
@@ -120,12 +129,10 @@ AC_SUBST(POPT_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl FIPS extensions (only for RHEL)
|
||||
AC_ARG_ENABLE([fips], AS_HELP_STRING([--enable-fips],[enable FIPS mode restrictions]),
|
||||
[with_fips=$enableval],
|
||||
[with_fips=no])
|
||||
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
dnl FIPS extensions
|
||||
AC_ARG_ENABLE([fips],
|
||||
AS_HELP_STRING([--enable-fips], [enable FIPS mode restrictions]))
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
AC_DEFINE(ENABLE_FIPS, 1, [Enable FIPS mode restrictions])
|
||||
|
||||
if test "x$enable_static" = "xyes" -o "x$enable_static_cryptsetup" = "xyes" ; then
|
||||
@@ -134,7 +141,7 @@ if test "x$with_fips" = "xyes"; then
|
||||
fi
|
||||
|
||||
AC_DEFUN([NO_FIPS], [
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
AC_MSG_ERROR([This option is not compatible with FIPS.])
|
||||
fi
|
||||
])
|
||||
@@ -142,12 +149,9 @@ AC_DEFUN([NO_FIPS], [
|
||||
dnl ==========================================================================
|
||||
dnl pwquality library (cryptsetup CLI only)
|
||||
AC_ARG_ENABLE([pwquality],
|
||||
AS_HELP_STRING([--enable-pwquality],
|
||||
[enable password quality checking using pwquality library]),
|
||||
[with_pwquality=$enableval],
|
||||
[with_pwquality=no])
|
||||
AS_HELP_STRING([--enable-pwquality], [enable password quality checking using pwquality library]))
|
||||
|
||||
if test "x$with_pwquality" = "xyes"; then
|
||||
if test "x$enable_pwquality" = "xyes"; then
|
||||
AC_DEFINE(ENABLE_PWQUALITY, 1, [Enable password quality checking using pwquality library])
|
||||
PKG_CHECK_MODULES([PWQUALITY], [pwquality >= 1.0.0],,
|
||||
AC_MSG_ERROR([You need pwquality library.]))
|
||||
@@ -159,13 +163,11 @@ fi
|
||||
dnl ==========================================================================
|
||||
dnl passwdqc library (cryptsetup CLI only)
|
||||
AC_ARG_ENABLE([passwdqc],
|
||||
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
|
||||
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]),
|
||||
[enable_passwdqc=$enableval],
|
||||
[enable_passwdqc=no])
|
||||
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
|
||||
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]))
|
||||
|
||||
case "$enable_passwdqc" in
|
||||
yes|no) use_passwdqc_config="" ;;
|
||||
""|yes|no) use_passwdqc_config="" ;;
|
||||
/*) use_passwdqc_config="$enable_passwdqc"; enable_passwdqc=yes ;;
|
||||
*) AC_MSG_ERROR([Unrecognized --enable-passwdqc parameter.]) ;;
|
||||
esac
|
||||
@@ -177,7 +179,7 @@ if test "x$enable_passwdqc" = "xyes"; then
|
||||
PASSWDQC_LIBS="-lpasswdqc"
|
||||
fi
|
||||
|
||||
if test "x$with_pwquality$enable_passwdqc" = "xyesyes"; then
|
||||
if test "x$enable_pwquality$enable_passwdqc" = "xyesyes"; then
|
||||
AC_MSG_ERROR([--enable-pwquality and --enable-passwdqc are mutually incompatible.])
|
||||
fi
|
||||
|
||||
@@ -185,20 +187,26 @@ dnl ==========================================================================
|
||||
dnl Crypto backend functions
|
||||
|
||||
AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
GCRYPT_REQ_VERSION=1.4.5
|
||||
else
|
||||
GCRYPT_REQ_VERSION=1.1.42
|
||||
fi
|
||||
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
|
||||
AC_ARG_ENABLE([gcrypt-pbkdf2], AS_HELP_STRING([--enable-gcrypt-pbkdf2],[force enable internal gcrypt PBKDF2]),
|
||||
|
||||
dnl libgcrypt rejects to use pkgconfig, use AM_PATH_LIBGCRYPT from gcrypt-devel here.
|
||||
dnl Do not require gcrypt-devel if other crypto backend is used.
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT],[
|
||||
AC_ARG_ENABLE([gcrypt-pbkdf2],
|
||||
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
|
||||
AS_HELP_STRING([--enable-gcrypt-pbkdf2], [force enable internal gcrypt PBKDF2]),
|
||||
if test "x$enableval" = "xyes"; then
|
||||
[use_internal_pbkdf2=0]
|
||||
else
|
||||
[use_internal_pbkdf2=1]
|
||||
fi,
|
||||
[AM_PATH_LIBGCRYPT([1.6.1], [use_internal_pbkdf2=0], [use_internal_pbkdf2=1])])
|
||||
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])
|
||||
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])],
|
||||
AC_MSG_ERROR([Missing support for gcrypt: install gcrypt and regenerate configure.]))
|
||||
|
||||
AC_MSG_CHECKING([if internal cryptsetup PBKDF2 is compiled-in])
|
||||
if test $use_internal_pbkdf2 = 0; then
|
||||
@@ -208,7 +216,9 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
NO_FIPS([])
|
||||
fi
|
||||
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_LIBS=$LIBS
|
||||
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
|
||||
AC_CHECK_LIB(gcrypt, gcry_check_version,,
|
||||
@@ -232,7 +242,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
CRYPTO_LIBS=$OPENSSL_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES([OPENSSL_STATIC], [openssl])
|
||||
@@ -242,7 +252,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
])
|
||||
|
||||
AC_DEFUN([CONFIGURE_NSS], [
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
AC_MSG_ERROR([Static build of cryptsetup is not supported with NSS.])
|
||||
fi
|
||||
|
||||
@@ -275,6 +285,7 @@ AC_DEFUN([CONFIGURE_KERNEL], [
|
||||
AC_DEFUN([CONFIGURE_NETTLE], [
|
||||
AC_CHECK_HEADERS(nettle/sha.h,,
|
||||
[AC_MSG_ERROR([You need Nettle cryptographic library.])])
|
||||
AC_CHECK_HEADERS(nettle/version.h)
|
||||
|
||||
saved_LIBS=$LIBS
|
||||
AC_CHECK_LIB(nettle, nettle_pbkdf2_hmac_sha256,,
|
||||
@@ -291,43 +302,42 @@ dnl ==========================================================================
|
||||
saved_LIBS=$LIBS
|
||||
|
||||
AC_ARG_ENABLE([static-cryptsetup],
|
||||
AS_HELP_STRING([--enable-static-cryptsetup],
|
||||
[enable build of static version of tools]))
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test x$enable_static = xno; then
|
||||
AS_HELP_STRING([--enable-static-cryptsetup], [enable build of static version of tools]))
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
if test "x$enable_static" = "xno"; then
|
||||
AC_MSG_WARN([Requested static cryptsetup build, enabling static library.])
|
||||
enable_static=yes
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(STATIC_TOOLS, test x$enable_static_cryptsetup = xyes)
|
||||
AM_CONDITIONAL(STATIC_TOOLS, test "x$enable_static_cryptsetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(cryptsetup,
|
||||
AS_HELP_STRING([--disable-cryptsetup],
|
||||
[disable cryptsetup support]),[], [enable_cryptsetup=yes])
|
||||
AM_CONDITIONAL(CRYPTSETUP, test x$enable_cryptsetup = xyes)
|
||||
AC_ARG_ENABLE([cryptsetup],
|
||||
AS_HELP_STRING([--disable-cryptsetup], [disable cryptsetup support]),
|
||||
[], [enable_cryptsetup=yes])
|
||||
AM_CONDITIONAL(CRYPTSETUP, test "x$enable_cryptsetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(veritysetup,
|
||||
AS_HELP_STRING([--disable-veritysetup],
|
||||
[disable veritysetup support]),[], [enable_veritysetup=yes])
|
||||
AM_CONDITIONAL(VERITYSETUP, test x$enable_veritysetup = xyes)
|
||||
AC_ARG_ENABLE([veritysetup],
|
||||
AS_HELP_STRING([--disable-veritysetup], [disable veritysetup support]),
|
||||
[], [enable_veritysetup=yes])
|
||||
AM_CONDITIONAL(VERITYSETUP, test "x$enable_veritysetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE([cryptsetup-reencrypt],
|
||||
AS_HELP_STRING([--disable-cryptsetup-reencrypt],
|
||||
[disable cryptsetup-reencrypt tool]),[], [enable_cryptsetup_reencrypt=yes])
|
||||
AM_CONDITIONAL(REENCRYPT, test x$enable_cryptsetup_reencrypt = xyes)
|
||||
AS_HELP_STRING([--disable-cryptsetup-reencrypt], [disable cryptsetup-reencrypt tool]),
|
||||
[], [enable_cryptsetup_reencrypt=yes])
|
||||
AM_CONDITIONAL(REENCRYPT, test "x$enable_cryptsetup_reencrypt" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(integritysetup,
|
||||
AS_HELP_STRING([--disable-integritysetup],
|
||||
[disable integritysetup support]),[], [enable_integritysetup=yes])
|
||||
AM_CONDITIONAL(INTEGRITYSETUP, test x$enable_integritysetup = xyes)
|
||||
AC_ARG_ENABLE([integritysetup],
|
||||
AS_HELP_STRING([--disable-integritysetup], [disable integritysetup support]),
|
||||
[], [enable_integritysetup=yes])
|
||||
AM_CONDITIONAL(INTEGRITYSETUP, test "x$enable_integritysetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(selinux,
|
||||
AS_HELP_STRING([--disable-selinux],
|
||||
[disable selinux support [default=auto]]),[], [])
|
||||
AC_ARG_ENABLE([selinux],
|
||||
AS_HELP_STRING([--disable-selinux], [disable selinux support [default=auto]]),
|
||||
[], [enable_selinux=yes])
|
||||
|
||||
AC_ARG_ENABLE([udev],
|
||||
AS_HELP_STRING([--disable-udev],
|
||||
[disable udev support]),[], enable_udev=yes)
|
||||
AS_HELP_STRING([--disable-udev], [disable udev support]),
|
||||
[], [enable_udev=yes])
|
||||
|
||||
dnl Try to use pkg-config for devmapper, but fallback to old detection
|
||||
PKG_CHECK_MODULES([DEVMAPPER], [devmapper >= 1.02.03],, [
|
||||
@@ -345,6 +355,8 @@ AC_CHECK_DECLS([dm_task_retry_remove], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([dm_task_deferred_remove], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([dm_device_has_mounted_fs], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([dm_device_has_holders], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([dm_device_get_name], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([DM_DEVICE_GET_TARGET_VERSION], [], [], [#include <libdevmapper.h>])
|
||||
AC_CHECK_DECLS([DM_UDEV_DISABLE_DISK_RULES_FLAG], [have_cookie=yes], [have_cookie=no], [#include <libdevmapper.h>])
|
||||
if test "x$enable_udev" = xyes; then
|
||||
if test "x$have_cookie" = xno; then
|
||||
@@ -357,20 +369,20 @@ LIBS=$saved_LIBS
|
||||
|
||||
dnl Check for JSON-C used in LUKS2
|
||||
PKG_CHECK_MODULES([JSON_C], [json-c])
|
||||
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
|
||||
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
|
||||
|
||||
dnl Crypto backend configuration.
|
||||
AC_ARG_WITH([crypto_backend],
|
||||
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [gcrypt]]),
|
||||
[], with_crypto_backend=gcrypt
|
||||
)
|
||||
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [openssl]]),
|
||||
[], [with_crypto_backend=openssl])
|
||||
|
||||
dnl Kernel crypto API backend needed for benchmark and tcrypt
|
||||
AC_ARG_ENABLE([kernel_crypto], AS_HELP_STRING([--disable-kernel_crypto],
|
||||
[disable kernel userspace crypto (no benchmark and tcrypt)]),
|
||||
[with_kernel_crypto=$enableval],
|
||||
[with_kernel_crypto=yes])
|
||||
AC_ARG_ENABLE([kernel_crypto],
|
||||
AS_HELP_STRING([--disable-kernel_crypto], [disable kernel userspace crypto (no benchmark and tcrypt)]),
|
||||
[], [enable_kernel_crypto=yes])
|
||||
|
||||
if test "x$with_kernel_crypto" = "xyes"; then
|
||||
if test "x$enable_kernel_crypto" = "xyes"; then
|
||||
AC_CHECK_HEADERS(linux/if_alg.h,,
|
||||
[AC_MSG_ERROR([You need Linux kernel headers with userspace crypto interface. (Or use --disable-kernel_crypto.)])])
|
||||
AC_DEFINE(ENABLE_AF_ALG, 1, [Enable using of kernel userspace crypto])
|
||||
@@ -384,36 +396,88 @@ case $with_crypto_backend in
|
||||
nettle) CONFIGURE_NETTLE([]) ;;
|
||||
*) AC_MSG_ERROR([Unknown crypto backend.]) ;;
|
||||
esac
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test $with_crypto_backend = gcrypt)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test $with_crypto_backend = openssl)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test $with_crypto_backend = nss)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test $with_crypto_backend = kernel)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test $with_crypto_backend = nettle)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test "$with_crypto_backend" = "gcrypt")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test "$with_crypto_backend" = "openssl")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test "$with_crypto_backend" = "nss")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test "$with_crypto_backend" = "kernel")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test "$with_crypto_backend" = "nettle")
|
||||
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_PBKDF2, test $use_internal_pbkdf2 = 1)
|
||||
AC_DEFINE_UNQUOTED(USE_INTERNAL_PBKDF2, [$use_internal_pbkdf2], [Use internal PBKDF2])
|
||||
|
||||
dnl Argon2 implementation
|
||||
AC_ARG_ENABLE(internal-argon2, AS_HELP_STRING([--disable-internal-argon2],
|
||||
[disable internal implementation of Argon2 PBKDF]),[], [enable_internal_argon2=yes])
|
||||
AC_ARG_ENABLE([internal-argon2],
|
||||
AS_HELP_STRING([--disable-internal-argon2], [disable internal implementation of Argon2 PBKDF]),
|
||||
[], [enable_internal_argon2=yes])
|
||||
|
||||
AC_ARG_ENABLE([libargon2], AS_HELP_STRING([--enable-libargon2],
|
||||
[enable external libargon2 (PHC) library (disables internal bundled version) ]),[], [enable_libargon2=no])
|
||||
AC_ARG_ENABLE([libargon2],
|
||||
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
|
||||
|
||||
if test x$enable_libargon2 = xyes ; then
|
||||
if test "x$enable_libargon2" = "xyes" ; then
|
||||
AC_CHECK_HEADERS(argon2.h,,
|
||||
[AC_MSG_ERROR([You need libargon2 development library installed.])])
|
||||
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
|
||||
PKG_CHECK_MODULES([LIBARGON2], [libargon2],,[LIBARGON2_LIBS="-largon2"])
|
||||
enable_internal_argon2=no
|
||||
else
|
||||
AC_MSG_WARN([Argon2 bundled (slow) reference implementation will be used, please consider to use system library with --enable-libargon2.])
|
||||
|
||||
AC_ARG_ENABLE([internal-sse-argon2],
|
||||
AS_HELP_STRING([--enable-internal-sse-argon2], [enable internal SSE implementation of Argon2 PBKDF]))
|
||||
|
||||
if test "x$enable_internal_sse_argon2" = "xyes"; then
|
||||
AC_MSG_CHECKING(if Argon2 SSE optimization can be used)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <emmintrin.h>
|
||||
__m128i testfunc(__m128i *a, __m128i *b) {
|
||||
return _mm_xor_si128(_mm_loadu_si128(a), _mm_loadu_si128(b));
|
||||
}
|
||||
]])],,[enable_internal_sse_argon2=no])
|
||||
AC_MSG_RESULT($enable_internal_sse_argon2)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x$enable_internal_argon2 = xyes ; then
|
||||
if test "x$enable_internal_argon2" = "xyes"; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
fi
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test x$enable_internal_argon2 = xyes)
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test "x$enable_internal_argon2" = "xyes")
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test "x$enable_internal_sse_argon2" = "xyes")
|
||||
|
||||
dnl Link with blkid to check for other device types
|
||||
AC_ARG_ENABLE([blkid],
|
||||
AS_HELP_STRING([--disable-blkid], [disable use of blkid for device signature detection and wiping]),
|
||||
[], [enable_blkid=yes])
|
||||
|
||||
if test "x$enable_blkid" = "xyes"; then
|
||||
PKG_CHECK_MODULES([BLKID], [blkid],[AC_DEFINE([HAVE_BLKID], 1, [Define to 1 to use blkid for detection of disk signatures.])],[LIBBLKID_LIBS="-lblkid"])
|
||||
|
||||
AC_CHECK_HEADERS(blkid/blkid.h,,[AC_MSG_ERROR([You need blkid development library installed.])])
|
||||
AC_CHECK_DECL([blkid_do_wipe],
|
||||
[ AC_DEFINE([HAVE_BLKID_WIPE], 1, [Define to 1 to use blkid_do_wipe.])
|
||||
enable_blkid_wipe=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECL([blkid_probe_step_back],
|
||||
[ AC_DEFINE([HAVE_BLKID_STEP_BACK], 1, [Define to 1 to use blkid_probe_step_back.])
|
||||
enable_blkid_step_back=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECLS([ blkid_reset_probe,
|
||||
blkid_probe_set_device,
|
||||
blkid_probe_filter_superblocks_type,
|
||||
blkid_do_safeprobe,
|
||||
blkid_do_probe,
|
||||
blkid_probe_lookup_value
|
||||
],,
|
||||
[AC_MSG_ERROR([Can not compile with blkid support, disable it by --disable-blkid.])],
|
||||
[#include <blkid/blkid.h>])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_BLKID, test "x$enable_blkid" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_WIPE, test "x$enable_blkid_wipe" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_STEP_BACK, test "x$enable_blkid_step_back" = "xyes")
|
||||
|
||||
dnl Magic for cryptsetup.static build.
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
|
||||
@@ -425,7 +489,7 @@ if test x$enable_static_cryptsetup = xyes; then
|
||||
LIBS="$saved_LIBS -static"
|
||||
PKG_CHECK_MODULES([DEVMAPPER_STATIC], [devmapper >= 1.02.27],,[
|
||||
DEVMAPPER_STATIC_LIBS=$DEVMAPPER_LIBS
|
||||
if test "x$enable_selinux" != xno; then
|
||||
if test "x$enable_selinux" = "xyes"; then
|
||||
AC_CHECK_LIB(sepol, sepol_bool_set)
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled)
|
||||
DEVMAPPER_STATIC_LIBS="$DEVMAPPER_STATIC_LIBS $LIBS"
|
||||
@@ -462,14 +526,19 @@ AC_SUBST([CRYPTO_STATIC_LIBS])
|
||||
|
||||
AC_SUBST([JSON_C_LIBS])
|
||||
AC_SUBST([LIBARGON2_LIBS])
|
||||
AC_SUBST([BLKID_LIBS])
|
||||
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION])
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
|
||||
|
||||
dnl ==========================================================================
|
||||
AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
|
||||
[use blocking /dev/random by default for key generator (otherwise use /dev/urandom)]),
|
||||
[default_rng=/dev/random], [default_rng=/dev/urandom])
|
||||
AC_ARG_ENABLE([dev-random],
|
||||
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
|
||||
if test "x$enable_dev_random" = "xyes"; then
|
||||
default_rng=/dev/random
|
||||
else
|
||||
default_rng=/dev/urandom
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RNG, ["$default_rng"], [default RNG type for key generator])
|
||||
|
||||
dnl ==========================================================================
|
||||
@@ -489,35 +558,12 @@ AC_DEFUN([CS_NUM_WITH], [AC_ARG_WITH([$1],
|
||||
[CS_DEFINE([$1], [$3], [$2])]
|
||||
)])
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl Python bindings
|
||||
AC_ARG_ENABLE([python], AS_HELP_STRING([--enable-python],[enable Python bindings]),
|
||||
[with_python=$enableval],
|
||||
[with_python=no])
|
||||
|
||||
AC_ARG_WITH([python_version],
|
||||
AS_HELP_STRING([--with-python_version=VERSION], [required Python version [2.6]]),
|
||||
[PYTHON_VERSION=$withval], [PYTHON_VERSION=2.6])
|
||||
|
||||
if test "x$with_python" = "xyes"; then
|
||||
AM_PATH_PYTHON([$PYTHON_VERSION])
|
||||
|
||||
AC_PATH_PROGS([PYTHON_CONFIG], [python${PYTHON_VERSION}-config python-config], [no])
|
||||
if test "${PYTHON_CONFIG}" = "no"; then
|
||||
AC_MSG_ERROR([cannot find python${PYTHON_VERSION}-config or python-config in PATH])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for python headers using $PYTHON_CONFIG --includes)
|
||||
PYTHON_INCLUDES=$($PYTHON_CONFIG --includes)
|
||||
AC_MSG_RESULT($PYTHON_INCLUDES)
|
||||
AC_SUBST(PYTHON_INCLUDES)
|
||||
|
||||
AC_MSG_CHECKING(for python libraries using $PYTHON_CONFIG --libs)
|
||||
PYTHON_LIBS=$($PYTHON_CONFIG --libs)
|
||||
AC_MSG_RESULT($PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_LIBS)
|
||||
fi
|
||||
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$with_python" = "xyes"])
|
||||
AC_DEFUN([CS_ABSPATH], [
|
||||
case "$1" in
|
||||
/*) ;;
|
||||
*) AC_MSG_ERROR([$2 argument must be an absolute path.]);;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [ripemd160])
|
||||
@@ -530,12 +576,22 @@ CS_STR_WITH([luks1-cipher], [cipher for LUKS1], [aes])
|
||||
CS_STR_WITH([luks1-mode], [cipher mode for LUKS1], [xts-plain64])
|
||||
CS_NUM_WITH([luks1-keybits],[key length in bits for LUKS1], [256])
|
||||
|
||||
AC_ARG_ENABLE([luks_adjust_xts_keysize], AS_HELP_STRING([--disable-luks-adjust-xts-keysize],
|
||||
[XTS mode requires two keys, double default LUKS keysize if needed]),
|
||||
[], [enable_luks_adjust_xts_keysize=yes])
|
||||
if test "x$enable_luks_adjust_xts_keysize" = "xyes"; then
|
||||
AC_DEFINE(ENABLE_LUKS_ADJUST_XTS_KEYSIZE, 1, [XTS mode - double default LUKS keysize if needed])
|
||||
fi
|
||||
|
||||
CS_STR_WITH([luks2-pbkdf], [Default PBKDF algorithm (pbkdf2 or argon2i/argon2id) for LUKS2], [argon2i])
|
||||
CS_NUM_WITH([luks1-iter-time], [PBKDF2 iteration time for LUKS1 (in ms)], [2000])
|
||||
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [800])
|
||||
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [131072])
|
||||
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [2000])
|
||||
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [1048576])
|
||||
CS_NUM_WITH([luks2-parallel-threads],[Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)], [4])
|
||||
|
||||
CS_STR_WITH([luks2-keyslot-cipher], [fallback cipher for LUKS2 keyslot (if data encryption is incompatible)], [aes-xts-plain64])
|
||||
CS_NUM_WITH([luks2-keyslot-keybits],[fallback key size for LUKS2 keyslot (if data encryption is incompatible)], [512])
|
||||
|
||||
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
|
||||
CS_NUM_WITH([loopaes-keybits],[key length in bits for loop-AES mode], [256])
|
||||
|
||||
@@ -550,17 +606,16 @@ CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
|
||||
|
||||
CS_STR_WITH([tmpfilesdir], [override default path to directory with systemd temporary files], [])
|
||||
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
|
||||
test "x$with_tmpfilesdir" == "xno" || {
|
||||
test "${with_tmpfilesdir:0:1}" = "/" || AC_MSG_ERROR([--with-tmpfilesdir argument must be an absolute path.])
|
||||
test "x$with_tmpfilesdir" = "xno" || {
|
||||
CS_ABSPATH([${with_tmpfilesdir}],[with-tmpfilesdir])
|
||||
DEFAULT_TMPFILESDIR=$with_tmpfilesdir
|
||||
AC_SUBST(DEFAULT_TMPFILESDIR)
|
||||
}
|
||||
AM_CONDITIONAL(CRYPTSETUP_TMPFILE, test -n "$DEFAULT_TMPFILESDIR")
|
||||
|
||||
|
||||
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/lock/cryptsetup])
|
||||
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/lock/cryptsetup
|
||||
test "${with_luks2_lock_path:0:1}" = "/" || AC_MSG_ERROR([--with-luks2-lock-path argument must be an absolute path.])
|
||||
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/cryptsetup])
|
||||
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/cryptsetup
|
||||
CS_ABSPATH([${with_luks2_lock_path}],[with-luks2-lock-path])
|
||||
DEFAULT_LUKS2_LOCK_PATH=$with_luks2_lock_path
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_PATH)
|
||||
|
||||
@@ -569,6 +624,18 @@ test -z "$with_luks2_lock_dir_perms" && with_luks2_lock_dir_perms=0700
|
||||
DEFAULT_LUKS2_LOCK_DIR_PERMS=$with_luks2_lock_dir_perms
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
|
||||
|
||||
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
|
||||
AC_ARG_WITH([default_luks_format],
|
||||
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS2]]),
|
||||
[], [with_default_luks_format=LUKS2])
|
||||
|
||||
case $with_default_luks_format in
|
||||
LUKS1) default_luks=CRYPT_LUKS1 ;;
|
||||
LUKS2) default_luks=CRYPT_LUKS2 ;;
|
||||
*) AC_MSG_ERROR([Unknown default LUKS format. Use LUKS1 or LUKS2 only.]) ;;
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_LUKS_FORMAT], [$default_luks], [default LUKS format version])
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_CONFIG_FILES([ Makefile
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
* Document cryptsetup exit codes.
|
||||
|
||||
2011-03-18 Milan Broz <mbroz@redhat.com>
|
||||
* Respect maximum keyfile size paramater.
|
||||
* Respect maximum keyfile size parameter.
|
||||
* Introduce maximum default keyfile size, add configure option.
|
||||
* Require the whole key read from keyfile in create command (broken in 1.2.0).
|
||||
* Fix offset option for loopaesOpen.
|
||||
@@ -195,7 +195,7 @@
|
||||
|
||||
2011-03-05 Milan Broz <mbroz@redhat.com>
|
||||
* Add exception to COPYING for binary distribution linked with OpenSSL library.
|
||||
* Set secure data flag (wipe all ioclt buffers) if devmapper library supports it.
|
||||
* Set secure data flag (wipe all ioctl buffers) if devmapper library supports it.
|
||||
|
||||
2011-01-29 Milan Broz <mbroz@redhat.com>
|
||||
* Fix mapping removal if device disappeared but node still exists.
|
||||
@@ -334,13 +334,13 @@
|
||||
* Version 1.1.0.
|
||||
|
||||
2010-01-10 Milan Broz <mbroz@redhat.com>
|
||||
* Fix initialisation of gcrypt duting luksFormat.
|
||||
* Convert hash name to lower case in header (fix sha1 backward comatible header)
|
||||
* Fix initialisation of gcrypt during luksFormat.
|
||||
* Convert hash name to lower case in header (fix sha1 backward compatible header)
|
||||
* Check for minimum required gcrypt version.
|
||||
|
||||
2009-12-30 Milan Broz <mbroz@redhat.com>
|
||||
* Fix key slot iteration count calculation (small -i value was the same as default).
|
||||
* The slot and key digest iteration minimun is now 1000.
|
||||
* The slot and key digest iteration minimum is now 1000.
|
||||
* The key digest iteration # is calculated from iteration time (approx 1/8 of that).
|
||||
* Version 1.1.0-rc4.
|
||||
|
||||
@@ -395,16 +395,16 @@
|
||||
* Require device device-mapper to build and do not use backend wrapper for dm calls.
|
||||
* Move memory locking and dm initialization to command layer.
|
||||
* Increase priority of process if memory is locked.
|
||||
* Add log macros and make logging modre consitent.
|
||||
* Add log macros and make logging more consistent.
|
||||
* Move command successful messages to verbose level.
|
||||
* Introduce --debug parameter.
|
||||
* Move device utils code and provide context parameter (for log).
|
||||
* Keyfile now must be provided by path, only stdin file descriptor is used (api only).
|
||||
* Do not call isatty() on closed keyfile descriptor.
|
||||
* Run performance check for PBKDF2 from LUKS code, do not mix hash algoritms results.
|
||||
* Run performance check for PBKDF2 from LUKS code, do not mix hash algorithms results.
|
||||
* Add ability to provide pre-generated master key and UUID in LUKS header format.
|
||||
* Add LUKS function to verify master key digest.
|
||||
* Move key slot manuipulation function into LUKS specific code.
|
||||
* Move key slot manipulation function into LUKS specific code.
|
||||
* Replace global options struct with separate parameters in helper functions.
|
||||
* Add new libcryptsetup API (documented in libcryptsetup.h).
|
||||
* Implement old API calls using new functions.
|
||||
@@ -412,7 +412,7 @@
|
||||
* Add --master-key-file option for luksFormat and luksAddKey.
|
||||
|
||||
2009-08-17 Milan Broz <mbroz@redhat.com>
|
||||
* Fix PBKDF2 speed calculation for large passhrases.
|
||||
* Fix PBKDF2 speed calculation for large passphrases.
|
||||
* Allow using passphrase provided in options struct for LuksOpen.
|
||||
* Allow restrict keys size in LuksOpen.
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
* Switch PBKDF2 from internal SHA1 to libgcrypt, make hash algorithm not hardcoded to SHA1 here.
|
||||
* Add required parameters for changing hash used in LUKS key setup scheme.
|
||||
* Do not export simple XOR helper now used only inside AF functions.
|
||||
* Completely remove internal SHA1 implementanion code, not needed anymore.
|
||||
* Completely remove internal SHA1 implementation code, not needed anymore.
|
||||
* Enable hash algorithm selection for LUKS through -h luksFormat option.
|
||||
|
||||
2009-07-28 Milan Broz <mbroz@redhat.com>
|
||||
@@ -636,7 +636,7 @@
|
||||
|
||||
2006-03-15 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* configure.in: 1.0.3-rc3. Most unplease release ever.
|
||||
* configure.in: 1.0.3-rc3. Most displease release ever.
|
||||
* lib/setup.c (__crypt_create_device): More verbose error message.
|
||||
|
||||
2006-02-26 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
@@ -705,7 +705,7 @@
|
||||
|
||||
2005-12-06 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explaination for -i.
|
||||
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explanation for -i.
|
||||
|
||||
2005-11-09 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
@@ -726,7 +726,7 @@
|
||||
|
||||
2005-09-08 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* lib/setup.c (get_key): Fixed another incompatiblity with
|
||||
* lib/setup.c (get_key): Fixed another incompatibility with
|
||||
original cryptsetup.
|
||||
|
||||
2005-08-20 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
@@ -816,7 +816,7 @@
|
||||
|
||||
* man/cryptsetup.1: Add man page.
|
||||
|
||||
* lib/setup.c: Remove unneccessary LUKS_write_phdr call, so the
|
||||
* lib/setup.c: Remove unnecessary LUKS_write_phdr call, so the
|
||||
phdr is written after passphrase reading, so the user can change
|
||||
his mind, and not have a partial written LUKS header on it's disk.
|
||||
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
LUKS2 on-disk format
|
||||
====================
|
||||
|
||||
Note: these are temporary documentation notes only.
|
||||
The more formal definition will be published later.
|
||||
|
||||
Design goals
|
||||
~~~~~~~~~~~~
|
||||
The LUKS2 is an on-disk storage format designed to
|
||||
provide simple key management, primarily intended for Full Disk
|
||||
Encryption based on dm-crypt.
|
||||
|
||||
The LUKS2 is highly inspired by LUKS1 format and in some
|
||||
specific situations (most of the default installations) can be converted
|
||||
in-place (in both ways - to and from LUKS1).
|
||||
|
||||
The LUKS2 format is designed to allow future updates of various
|
||||
parts without the need to modify binary structures.
|
||||
|
||||
On-disk format provides redundancy of metadata, detection
|
||||
of metadata corruption and automatic repair from metadata copy.
|
||||
|
||||
NOTE: For security reasons, there is no redundancy in keyslots
|
||||
binary data (encrypted keys) but format allows updating to redundant
|
||||
keyslot encryption in future (add forward error correction codes
|
||||
is one possibility).
|
||||
|
||||
On-disk structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The LUKS2 header contains three parts:
|
||||
- binary header (one 4096 bytes sector)
|
||||
- area for metadata stored in JSON format
|
||||
- keyslot area (per-context binary data).
|
||||
|
||||
The binary header and JSON area are stored twice to increase
|
||||
redundancy. Keyslot area is allocated per-demand, and it is stored only once.
|
||||
|
||||
The basic on-disk structure is then
|
||||
|
||||
0 4096
|
||||
| bin hdr1 | JSON ... | bin hdr2 | JSON ... | Keyslot data | <padding> | (data payload)
|
||||
|
||||
Binary header
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The binary header is intended for quick scanning (by blkid and udev) and contains
|
||||
magic string to detect the device, basic information (labels), header size information
|
||||
and metadata checksum.
|
||||
Checksum covers both binary data and following JSON area and is calculated
|
||||
with checksum fields zeroed. By default plain SHA256 checksum is used.
|
||||
|
||||
The primary binary header is always stored in sector 0 of the device.
|
||||
|
||||
The C structure of binary header (see luks2.h) is
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
||||
#define LUKS2_MAGIC_L 6
|
||||
#define LUKS2_UUID_L 40
|
||||
#define LUKS2_LABEL_L 48
|
||||
#define LUKS2_SALT_L 64
|
||||
#define LUKS2_CHECKSUM_ALG_L 32
|
||||
#define LUKS2_CHECKSUM_L 64
|
||||
|
||||
struct luks2_hdr_disk {
|
||||
char magic[LUKS2_MAGIC_L]; /* "LUKS\xba\xbe" (1st) or "SKUL\xba\be" (2nd) */
|
||||
uint16_t version; /* Version 2 */
|
||||
uint64_t hdr_size; /* in bytes, including JSON area */
|
||||
uint64_t seqid; /* sequence ID, increased on every update */
|
||||
char label[LUKS2_LABEL_L]; /* ASCII label or empty */
|
||||
char checksum_alg[LUKS2_CHECKSUM_ALG_L]; /* checksum algorithm, "sha256" */
|
||||
uint8_t salt[LUKS2_SALT_L]; /* random salt, unique for every header */
|
||||
char uuid[LUKS2_UUID_L]; /* UUID of device */
|
||||
char subsystem[LUKS2_LABEL_L]; /* owner subsystem label or empty */
|
||||
uint64_t hdr_offset; /* header offset from device start in bytes */
|
||||
char _padding[184]; /* must be zeroed */
|
||||
uint8_t csum[LUKS2_CHECKSUM_L]; /* header checksum */
|
||||
char _padding4096[7*512]; /* must be zeroed */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
The LUKS1 compatible field (magic, UUID) are placed intentionally on the same offsets.
|
||||
The header version must be set to 2.
|
||||
The UUID is the same format as in LUKS1.
|
||||
|
||||
Magic string differs between the first and second header.
|
||||
|
||||
The hdr_offset must match physical header offset on the device.
|
||||
If hdr_offset does not match, the header is misplaced and must not be used.
|
||||
(It is a prevention to partition resize or manipulation with device start offset.)
|
||||
|
||||
The hdr_size contains the size of the binary header and JSON data area.
|
||||
The offset and size of the second (backup) header must match to these data.
|
||||
(Prevention to rewrite of a header with different JSON area size.)
|
||||
|
||||
There are two labels - label and subsystem. Content of these fields will be visible
|
||||
in UDEV/blkid scan and can be used for similar purposes as a filesystem label.
|
||||
These fields are by default empty.
|
||||
|
||||
The salt field in binary header is generated by an RNG and is different for
|
||||
every header, even the backup header must contain a different salt.
|
||||
The salt in binary header is not used after the header is read, the main intention
|
||||
is to avoid deduplication of the header sector.
|
||||
The salt must be regenerated on every header repair (but not on regular update).
|
||||
|
||||
The sequential number (seqid) is a counter that is always increased when a new
|
||||
update of the header is written. The header with higher seqid is more recent and
|
||||
is used for recovery (if there are two headers with different seqid, the
|
||||
more recent one is automatically used).
|
||||
|
||||
The rest of binary header must be zeroed.
|
||||
|
||||
JSON area
|
||||
~~~~~~~~~
|
||||
The JSON area starts immediately after the binary header. Its size is set
|
||||
by binary header hdr_size field (JSON area size = hdr_size - 4096).
|
||||
|
||||
The area contains metadata in JSON format and is fixed. Unused remainder
|
||||
of the area must be empty.
|
||||
|
||||
The header cannot store larger metadata that this fixed buffer and header
|
||||
size must be set properly during format. For now, only areas with 14 kB
|
||||
header (4kB binary header + 14kB JSON area) is created during format.
|
||||
|
||||
The JSON is structured to be able to describe system in very generic way,
|
||||
but LUKS2 intentionally limits options to values that are supportable
|
||||
in implemented version.
|
||||
|
||||
JSON structure is as follows:
|
||||
|
||||
Mandatory sections (must be present but some can be empty):
|
||||
- config
|
||||
- keyslots
|
||||
- digests
|
||||
- segments
|
||||
- tokens
|
||||
|
||||
Except for config section, all section contains array of objects that must be named
|
||||
as number (unsigned integer) - for example keyslot "0", "1" etc.
|
||||
Every object is typed (must contain attribute "type").
|
||||
According to type, library decides how to handle (or ignore) such an object.
|
||||
|
||||
Binary data inside JSON (for example salt) is stored in Hexa64 encoding.
|
||||
|
||||
If a value is needed to be stored as a 64bit integer (usually offset or size),
|
||||
it is stored in text format and later converted to the 64bit integer.
|
||||
(JSON cannot store 64bit integers directly.)
|
||||
|
||||
Config section
|
||||
~~~~~~~~~~~~~~
|
||||
Config contains information about JSON buffer size (cross-checked with binary header),
|
||||
keyslot area size and optional object with activation flags.
|
||||
|
||||
The "flags" section is array of activation flags that are automatically used
|
||||
when LUKS device is activated (for example it can unconditionally allow TRIM/discard
|
||||
functionality on the encrypted device).
|
||||
|
||||
Segments sections
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The segment is an encrypted area on the disk containing data (in LUKS1 often
|
||||
mentioned as a data payload).
|
||||
For now, only one data area is available for the user.
|
||||
(More segments will be later used for on-line re-encryption functionality.)
|
||||
|
||||
Segments contain definition about encryption parameters, sector size and
|
||||
start and length of the segments. By default, the segment starts directly
|
||||
after the LUKS2 header and is marked as "dynamic" (it automatically detects
|
||||
the size of the available device).
|
||||
|
||||
Optionally it can contain information about data integrity protection,
|
||||
then the data segments is formatted as dm-integrity device and dm-crypt
|
||||
encryption is stacked above.
|
||||
|
||||
To activate a segment, there must be at least one digest linked to it.
|
||||
|
||||
Keyslots section
|
||||
~~~~~~~~~~~~~~~~
|
||||
Keyslot object contains information stored key - area, where it is stored
|
||||
(keyslot data), encryption, anti-forensic function, and Key Derivation Function
|
||||
and its parameters (PBKDF type, costs, salt).
|
||||
|
||||
For now, only internal "luks2" keyslot type is available, it uses the same logic
|
||||
as LUKS1 keyslot, but allows to define per-keyslot algorithms
|
||||
(for example different PBKDF).
|
||||
|
||||
Digests section
|
||||
~~~~~~~~~~~~~~~
|
||||
The digest is used to verify that volume key decrypted from a keyslot is correct.
|
||||
A digest is linked to keyslots and segment.
|
||||
|
||||
For now, only "pbkdf2" digest (LUKS1 compatible digest that uses PBKDF2)
|
||||
is supported.
|
||||
|
||||
Tokens section
|
||||
~~~~~~~~~~~~~~
|
||||
A token is an object that can describe "how to get passphrase or key" to unlock
|
||||
particular keyslot or it can be used t store any additional data (even unrelated
|
||||
to a keyslot).
|
||||
This area can be user configurable, and libcryptsetup provides interface to
|
||||
store used data directly in JSON format.
|
||||
Some token types are implemented internally, for now, there is only "luks2-keyring".
|
||||
type. This token type tries to load unlocking passphrase from kernel keyring
|
||||
with stored identification.
|
||||
|
||||
There can be external application that uses token objects to store metadata and
|
||||
implements bindings to specific hardware (TPM etc.).
|
||||
|
||||
LUKS2 JSON Format Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
For illustration this is example of a LUKS2 device JSON:
|
||||
|
||||
{
|
||||
"keyslots":{
|
||||
"0":{
|
||||
"type":"luks2",
|
||||
"key_size":32,
|
||||
"kdf":{
|
||||
"type":"argon2i",
|
||||
"time":181,
|
||||
"memory":1024,
|
||||
"cpus":4,
|
||||
"salt":"Xfc5ScS8tCLrdbt6jtyWsBjCwAn3Msn\/enOYaAq8PEo="
|
||||
},
|
||||
"af":{
|
||||
"type":"luks1",
|
||||
"hash":"sha256",
|
||||
"stripes":4000
|
||||
},
|
||||
"area":{
|
||||
"type":"raw",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"key_size":32,
|
||||
"offset":"32768",
|
||||
"size":"131072"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tokens":{
|
||||
"0":{
|
||||
"type":"luks2-keyring",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"key_description":"my-token"
|
||||
}
|
||||
},
|
||||
"segments":{
|
||||
"0":{
|
||||
"type":"crypt",
|
||||
"offset":"4194304",
|
||||
"iv_tweak":"0",
|
||||
"size":"dynamic",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"sector_size":512
|
||||
}
|
||||
},
|
||||
"digests":{
|
||||
"0":{
|
||||
"type":"pbkdf2",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"segments":[
|
||||
"0"
|
||||
],
|
||||
"hash":"sha256",
|
||||
"iterations":155298,
|
||||
"salt":"WgMOideLECc5hfnmFVu3bwttJpkfnpf2RayE2WhP8zU=",
|
||||
"digest":"olobPk9pc0GItqofH78aMPmRaOZIbRevlvSlTZ91NLI="
|
||||
}
|
||||
},
|
||||
"config":{
|
||||
"json_size":"12288",
|
||||
"keyslots_size":"4161536",
|
||||
"flags":[
|
||||
"allow-discards"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
* @subsection cformat crypt_format() - header and payload on mutual device
|
||||
* This section covers basic use cases for formatting LUKS devices. Format operation
|
||||
* sets device type in context and in case of LUKS header is written at the beginning
|
||||
* of block device. In the example bellow we use the scenario where LUKS header and data
|
||||
* of block device. In the example below we use the scenario where LUKS header and data
|
||||
* are both stored on the same device. There's also a possibility to store header and
|
||||
* data separately.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An example of using logging through libcryptsetup API
|
||||
* libcryptsetup API log example
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -25,10 +25,8 @@
|
||||
#include <libcryptsetup.h>
|
||||
|
||||
/*
|
||||
* This is an example of function that can be registered using crypt_set_log_callback API.
|
||||
* This is an example of crypt_set_log_callback API callback.
|
||||
*
|
||||
* Its prototype is void (*log)(int level, const char *msg, void *usrptr) as defined
|
||||
* in crypt_set_log_callback
|
||||
*/
|
||||
static void simple_syslog_wrapper(int level, const char *msg, void *usrptr)
|
||||
{
|
||||
@@ -71,7 +69,7 @@ int main(void)
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* crypt_set_log_callback() - register a log function for crypt context */
|
||||
/* crypt_set_log_callback() - register a log callback for crypt context */
|
||||
crypt_set_log_callback(cd, &simple_syslog_wrapper, (void *)usrprefix);
|
||||
|
||||
/* send messages ithrough the crypt_log() interface */
|
||||
@@ -83,7 +81,7 @@ int main(void)
|
||||
/* release crypt context */
|
||||
crypt_free(cd);
|
||||
|
||||
/* Initialize default (global) log function */
|
||||
/* Initialize default (global) log callback */
|
||||
crypt_set_log_callback(NULL, &simple_syslog_wrapper, NULL);
|
||||
|
||||
crypt_log(NULL, CRYPT_LOG_NORMAL, "This is normal log message");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An example of using LUKS device through libcryptsetup API
|
||||
* libcryptsetup API - using LUKS device example
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -29,23 +29,18 @@
|
||||
static int format_and_add_keyslots(const char *path)
|
||||
{
|
||||
struct crypt_device *cd;
|
||||
struct crypt_params_luks1 params;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* crypt_init() call precedes most of operations of cryptsetup API. The call is used
|
||||
* to initialize crypt device context stored in structure referenced by _cd_ in
|
||||
* the example. Second parameter is used to pass underlaying device path.
|
||||
* The crypt_init() call is used to initialize crypt_device context,
|
||||
* The path parameter specifies a device path.
|
||||
*
|
||||
* Note:
|
||||
* If path refers to a regular file it'll be attached to a first free loop device.
|
||||
* crypt_init() operation fails in case there's no more loop device available.
|
||||
* Also, loop device will have the AUTOCLEAR flag set, so the file loopback will
|
||||
* be detached automatically.
|
||||
* For path, you can use either link to a file or block device.
|
||||
* The loopback device will be detached automatically.
|
||||
*/
|
||||
|
||||
r = crypt_init(&cd, path);
|
||||
if (r < 0 ) {
|
||||
if (r < 0) {
|
||||
printf("crypt_init() failed for %s.\n", path);
|
||||
return r;
|
||||
}
|
||||
@@ -53,73 +48,37 @@ static int format_and_add_keyslots(const char *path)
|
||||
printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));
|
||||
|
||||
/*
|
||||
* So far no data were written on your device. This will change with call of
|
||||
* crypt_format() only if you specify CRYPT_LUKS1 as device type.
|
||||
* So far, no data were written to the device.
|
||||
*/
|
||||
printf("Device %s will be formatted to LUKS device after 5 seconds.\n"
|
||||
printf("Device %s will be formatted as a LUKS device after 5 seconds.\n"
|
||||
"Press CTRL+C now if you want to cancel this operation.\n", path);
|
||||
sleep(5);
|
||||
|
||||
|
||||
/*
|
||||
* Prepare LUKS format parameters
|
||||
*
|
||||
* hash parameter defines PBKDF2 hash algorithm used in LUKS header.
|
||||
* For compatibility reason we use SHA1 here.
|
||||
*/
|
||||
params.hash = "sha1";
|
||||
|
||||
/*
|
||||
* data_alignment parameter is relevant only in case of the luks header
|
||||
* and the payload are both stored on same device.
|
||||
*
|
||||
* if you set data_alignment = 0, cryptsetup will autodetect
|
||||
* data_alignment according to underlaying device topology.
|
||||
*/
|
||||
params.data_alignment = 0;
|
||||
|
||||
/*
|
||||
* data_device parameter defines that no external device
|
||||
* for luks header will be used
|
||||
*/
|
||||
params.data_device = NULL;
|
||||
|
||||
/*
|
||||
* NULLs for uuid and volume_key means that these attributes will be
|
||||
* generated during crypt_format(). Volume key is generated with respect
|
||||
* to key size parameter passed to function.
|
||||
*
|
||||
* crypt_format() checks device size (LUKS header must fit there).
|
||||
* generated during crypt_format().
|
||||
*/
|
||||
r = crypt_format(cd, /* crypt context */
|
||||
CRYPT_LUKS1, /* LUKS1 is standard LUKS header */
|
||||
CRYPT_LUKS2, /* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
|
||||
"aes", /* used cipher */
|
||||
"xts-plain64", /* used block mode and IV generator*/
|
||||
"xts-plain64", /* used block mode and IV */
|
||||
NULL, /* generate UUID */
|
||||
NULL, /* generate volume key from RNG */
|
||||
256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */
|
||||
¶ms); /* parameters above */
|
||||
512 / 8, /* 512bit key - here AES-256 in XTS mode, size is in bytes */
|
||||
NULL); /* default parameters */
|
||||
|
||||
if(r < 0) {
|
||||
if (r < 0) {
|
||||
printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device now contains LUKS1 header, but there is
|
||||
* no active keyslot with encrypted volume key yet.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cryptt_kesylot_add_* call stores volume_key in encrypted form into keyslot.
|
||||
* Without keyslot you can't manipulate with LUKS device after the context will be freed.
|
||||
* The device now contains a LUKS header, but there is no active keyslot.
|
||||
*
|
||||
* To create a new keyslot you need to supply the existing one (to get the volume key from) or
|
||||
* you need to supply the volume key.
|
||||
* crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
|
||||
*
|
||||
* After format, we have volume key stored internally in context so add new keyslot
|
||||
* using this internal volume key.
|
||||
* After format, the volume key is stored internally.
|
||||
*/
|
||||
r = crypt_keyslot_add_by_volume_key(cd, /* crypt context */
|
||||
CRYPT_ANY_SLOT, /* just use first free slot */
|
||||
@@ -137,8 +96,8 @@ static int format_and_add_keyslots(const char *path)
|
||||
printf("The first keyslot is initialized.\n");
|
||||
|
||||
/*
|
||||
* Add another keyslot, now using the first keyslot.
|
||||
* It will decrypt volume key from the first keyslot and creates new one with another passphrase.
|
||||
* Add another keyslot, now authenticating with the first keyslot.
|
||||
* It decrypts the volume key from the first keyslot and creates a new one with the specified passphrase.
|
||||
*/
|
||||
r = crypt_keyslot_add_by_passphrase(cd, /* crypt context */
|
||||
CRYPT_ANY_SLOT, /* just use first free slot */
|
||||
@@ -164,21 +123,18 @@ static int activate_and_check_status(const char *path, const char *device_name)
|
||||
|
||||
/*
|
||||
* LUKS device activation example.
|
||||
* It's sequence of sub-steps: device initialization, LUKS header load
|
||||
* and the device activation itself.
|
||||
*/
|
||||
r = crypt_init(&cd, path);
|
||||
if (r < 0 ) {
|
||||
if (r < 0) {
|
||||
printf("crypt_init() failed for %s.\n", path);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypt_load() is used to load the LUKS header from block device
|
||||
* into crypt_device context.
|
||||
* crypt_load() is used to load existing LUKS header from a block device
|
||||
*/
|
||||
r = crypt_load(cd, /* crypt context */
|
||||
CRYPT_LUKS1, /* requested type */
|
||||
CRYPT_LUKS, /* requested type - here LUKS of any type */
|
||||
NULL); /* additional parameters (not used) */
|
||||
|
||||
if (r < 0) {
|
||||
@@ -188,11 +144,11 @@ static int activate_and_check_status(const char *path, const char *device_name)
|
||||
}
|
||||
|
||||
/*
|
||||
* Device activation creates device-mapper devie mapping with name device_name.
|
||||
* Device activation creates a device-mapper device with the specified name.
|
||||
*/
|
||||
r = crypt_activate_by_passphrase(cd, /* crypt context */
|
||||
device_name, /* device name to activate */
|
||||
CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */
|
||||
CRYPT_ANY_SLOT,/* the keyslot use (try all here) */
|
||||
"foo", 3, /* passphrase */
|
||||
CRYPT_ACTIVATE_READONLY); /* flags */
|
||||
if (r < 0) {
|
||||
@@ -201,13 +157,13 @@ static int activate_and_check_status(const char *path, const char *device_name)
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("LUKS device %s/%s is active.\n", crypt_get_dir(), device_name);
|
||||
printf("%s device %s/%s is active.\n", crypt_get_type(cd), crypt_get_dir(), device_name);
|
||||
printf("\tcipher used: %s\n", crypt_get_cipher(cd));
|
||||
printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
|
||||
printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
|
||||
|
||||
/*
|
||||
* Get info about active device (query DM backend)
|
||||
* Get info about the active device.
|
||||
*/
|
||||
r = crypt_get_active_device(cd, device_name, &cad);
|
||||
if (r < 0) {
|
||||
@@ -235,7 +191,7 @@ static int handle_active_device(const char *device_name)
|
||||
int r;
|
||||
|
||||
/*
|
||||
* crypt_init_by_name() initializes device context and loads LUKS header from backing device
|
||||
* crypt_init_by_name() initializes context by an active device-mapper name
|
||||
*/
|
||||
r = crypt_init_by_name(&cd, device_name);
|
||||
if (r < 0) {
|
||||
@@ -252,7 +208,7 @@ static int handle_active_device(const char *device_name)
|
||||
}
|
||||
|
||||
/*
|
||||
* crypt_deactivate() is used to deactivate device
|
||||
* crypt_deactivate() is used to deactivate a device
|
||||
*/
|
||||
r = crypt_deactivate(cd, device_name);
|
||||
if (r < 0) {
|
||||
|
||||
BIN
docs/on-disk-format-luks2.pdf
Normal file
BIN
docs/on-disk-format-luks2.pdf
Normal file
Binary file not shown.
Binary file not shown.
@@ -15,7 +15,7 @@ Important changes
|
||||
* NSS (because of missing ripemd160 it cannot provide full backward compatibility)
|
||||
* kernel userspace API (provided by kernel 2.6.38 and above)
|
||||
(Note that kernel userspace backend is very slow for this type of operation.
|
||||
But it can be usefull for embedded systems, because you can avoid userspace
|
||||
But it can be useful for embedded systems, because you can avoid userspace
|
||||
crypto library completely.)
|
||||
|
||||
Backend is selected during configure time, using --with-crypto_backend option.
|
||||
|
||||
@@ -89,7 +89,7 @@ WARNING: This release removes old deprecated API from libcryptsetup
|
||||
(It can be used to simulate trivial hidden disk concepts.)
|
||||
|
||||
libcryptsetup API changes:
|
||||
* Added options to suport detached metadata device
|
||||
* Added options to support detached metadata device
|
||||
crypt_init_by_name_and_header()
|
||||
crypt_set_data_device()
|
||||
* Add crypt_last_error() API call.
|
||||
|
||||
@@ -46,7 +46,7 @@ Side effect of reencryption is that final device will contain
|
||||
only ciphertext (for all sectors) so even if device was not properly
|
||||
wiped by random data, after reencryption you cannot distinguish
|
||||
which sectors are used.
|
||||
(Reecryption is done always for the whole device.)
|
||||
(Reencryption is done always for the whole device.)
|
||||
|
||||
There are for sure bugs, please TEST IT IN TEST ENVIRONMENT before
|
||||
use for your data.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Cryptsetup 2.0.0 RC1 Release Notes
|
||||
==================================
|
||||
Release candidate with experimental features.
|
||||
Cryptsetup 2.0.0 Release Notes
|
||||
==============================
|
||||
Stable release with experimental features.
|
||||
|
||||
This version introduces a new on-disk LUKS2 format.
|
||||
|
||||
@@ -12,18 +12,28 @@ major version for all public symbols.
|
||||
Most of the old functions are fully backward compatible, so only
|
||||
recompilation of programs should be needed.
|
||||
|
||||
Please note that authenticated disk encryption, noncryptographic
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
Please do not use it without properly configured backup or in
|
||||
production systems.
|
||||
|
||||
Until final 2.0 version is released, the new LUKS2 format
|
||||
could still internally change if a major problem is found.
|
||||
To provide all security features of authenticated encryption we need
|
||||
better nonce-reuse resistant algorithm in kernel (see note below).
|
||||
For now, please use authenticated encryption as experimental feature.
|
||||
|
||||
The library API calls (versioned symbols) are now stable and
|
||||
will not change in an incompatible way.
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.0-RC1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Limit KDF requested (for format) memory by available physical memory.
|
||||
On some systems too high requested amount of memory causes OOM killer
|
||||
to kill the process (instead of returning ENOMEM).
|
||||
We never try to use more than half of available physical memory.
|
||||
|
||||
* Ignore device alignment if it is not multiple of minimal-io.
|
||||
Some USB enclosures seems to report bogus topology info that
|
||||
prevents to use LUKS detached header.
|
||||
|
||||
Changes since version 2.0.0-RC0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -248,12 +258,13 @@ The newly added features in LUKS2 include:
|
||||
|
||||
For testing of authenticated encryption, these algorithms work for now:
|
||||
|
||||
1) aes-xts-random with hmac-sha256 or hmac-sha512 as the authentication tag.
|
||||
(Authentication key for HMAC is independently generated. This mode is very slow.)
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity hmac-sha256
|
||||
1) aes-xts-plain64 with hmac-sha256 or hmac-sha512 as the authentication tag.
|
||||
(Common FDE mode + independent authentication tag. Authentication key
|
||||
for HMAC is independently generated. This mode is very slow.)
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-plain64 --integrity hmac-sha256
|
||||
|
||||
2) aes-gcm-random (native AEAD mode)
|
||||
DO NOT USE in production. The GCM mode uses only 96-bit nonce,
|
||||
DO NOT USE in production! The GCM mode uses only 96-bit nonce,
|
||||
and possible collision means fatal security problem.
|
||||
GCM mode has very good hardware support through AES-NI, so it is useful
|
||||
for performance testing.
|
||||
@@ -267,17 +278,8 @@ The newly added features in LUKS2 include:
|
||||
should work as well. The mode 1) and 2) should be compatible with IEEE 1619.1
|
||||
standard recommendation.
|
||||
|
||||
You can also store only random IV in tag without integrity protection.
|
||||
|
||||
Note that using random IV forces the system to pseudorandomly change the whole
|
||||
sector on every write without removing parallel processing of XTS mode.
|
||||
In cryptography, we can say that this will provide indistinguishability under
|
||||
chosen plaintext attack (IND-CPA) that cannot be achieved in legacy
|
||||
FDE systems. On the other side, if stored random IV is corrupted, the sector
|
||||
is no longer decrypted properly.
|
||||
|
||||
To use only random IV (no integrity protection), just specify "none" integrity.
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity none
|
||||
There will be better suitable authenticated modes available soon
|
||||
For now we are just preparing framework to enable it (and hopefully improve security of FDE).
|
||||
|
||||
FDE authenticated encryption is not a replacement for filesystem layer
|
||||
authenticated encryption. The goal is to provide at least something because
|
||||
@@ -296,7 +298,7 @@ The newly added features in LUKS2 include:
|
||||
To solve this problem, a new PBKDF, based on so-called memory-hard functions
|
||||
can be used. Key derivation with memory-hard function requires a certain
|
||||
amount of memory to compute its output. The memory requirement is very
|
||||
costly for GPUs and prevents these systems to operate ineffectively,
|
||||
costly for GPUs and prevents these systems to operate effectively,
|
||||
increasing cost for attackers.
|
||||
|
||||
LUKS2 introduces support for Argon2i and Argon2id as a PBKDF.
|
||||
@@ -481,7 +483,7 @@ Other changes
|
||||
For LUKS2 it is always better to specify full settings (do not rely on default
|
||||
cost values).
|
||||
For example, we can set to use Argon2id with iteration cost 5, memory 128000
|
||||
and paralell set 1:
|
||||
and parallel set 1:
|
||||
$ cryptsetup luksFormat --type luks2 <device> \
|
||||
--pbkdf argon2id --pbkdf-force-iterations 5 --pbkdf-memory 128000 --pbkdf-parallel 1
|
||||
|
||||
@@ -565,21 +567,24 @@ These new calls are now exported, for details see libcryptsetup.h:
|
||||
crypt_keyfile_read;
|
||||
crypt_wipe;
|
||||
|
||||
Unfinished things & TODO for next RC or future
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Offline re-encrypt tool supports only LUKS1 format for now (patches are
|
||||
on the way).
|
||||
* Offline re-encrypt tool LUKS2 support is currently limited.
|
||||
There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition,
|
||||
once these algorithms are available in kernel.
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
(https://competitions.cr.yp.to/caesar.html) once these algorithms are available
|
||||
in kernel (more on this later).
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collison probability is not negligible).
|
||||
For the GCM, nonce collision is a fatal problem.
|
||||
|
||||
* Authenticated encryption do not set encryption for dm-integrity journal.
|
||||
|
||||
@@ -588,17 +593,13 @@ Unfinished things & TODO for next RC or future
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* Some utilities (blkid, systemd-cryptsetup) will need small updates to support
|
||||
LUKS2 format.
|
||||
* Some utilities (blkid, systemd-cryptsetup) have already support for LUKS
|
||||
but not yet in released version (support in crypttab etc).
|
||||
|
||||
* There are some examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
We will document these examples later in release notes for next RC.
|
||||
|
||||
* The distribution archive is now very big because of some testing images that do not compress
|
||||
well. Some cleaning is needed here.
|
||||
|
||||
* A lot of ideas are hidden inside the LUKS2 design that is not yet used or
|
||||
described here, let's try if the basics work first :-)
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated soon in favor
|
||||
of python bindings to libblockdev library (that can already handle LUKS1 devices).
|
||||
109
docs/v2.0.1-ReleaseNotes
Normal file
109
docs/v2.0.1-ReleaseNotes
Normal file
@@ -0,0 +1,109 @@
|
||||
Cryptsetup 2.0.1 Release Notes
|
||||
==============================
|
||||
Stable and bug-fix release with experimental features.
|
||||
|
||||
This version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* To store volume key into kernel keyring, kernel 4.15 with dm-crypt 1.18.1
|
||||
is required. If a volume key is stored in keyring (LUKS2 only),
|
||||
the dm-crypt v1.15.0 through v1.18.0 contains a serious bug that may cause
|
||||
data corruption for ciphers with ESSIV.
|
||||
(The key for ESSIV is zeroed because of code misplacement.)
|
||||
This bug is not present for LUKS1 or any other IVs used in LUKS modes.
|
||||
This change is not visible to the user (except dmsetup output).
|
||||
|
||||
* Increase maximum allowed PBKDF memory-cost limit to 4 GiB.
|
||||
The Argon2 PBKDF uses 1GiB by default; this is also limited by the amount
|
||||
of physical memory available (maximum is half of the physical memory).
|
||||
|
||||
* Use /run/cryptsetup as default for cryptsetup locking dir.
|
||||
There were problems with sharing /run/lock with lockdev, and in the early
|
||||
boot, the directory was missing.
|
||||
The directory can be changed with --with-luks2-lock-path and
|
||||
--with-luks2-lock-dir-perms configure switches.
|
||||
|
||||
* Introduce new 64-bit byte-offset *keyfile_device_offset functions.
|
||||
|
||||
The keyfile interface was designed, well, for keyfiles. Unfortunately,
|
||||
there are user cases where a keyfile can be placed on a device, and
|
||||
size_t offset can overflow on 32-bit systems.
|
||||
|
||||
New set of functions that allow 64-bit offsets even on 32bit systems
|
||||
are now available:
|
||||
|
||||
- crypt_resume_by_keyfile_device_offset
|
||||
- crypt_keyslot_add_by_keyfile_device_offset
|
||||
- crypt_activate_by_keyfile_device_offset
|
||||
- crypt_keyfile_device_read
|
||||
|
||||
The new functions have added the _device_ in name.
|
||||
Old functions are just internal wrappers around these.
|
||||
|
||||
Also cryptsetup --keyfile-offset and --new-keyfile-offset now allows
|
||||
64-bit offsets as parameters.
|
||||
|
||||
* Add error hint for wrongly formatted cipher strings in LUKS1 and
|
||||
properly fail in luksFormat if cipher format is missing required IV.
|
||||
For now, crypto API quietly used cipher without IV if a cipher
|
||||
algorithm without IV specification was used (e.g., aes-xts).
|
||||
This caused fail later during activation.
|
||||
|
||||
* Configure check for a recent Argon2 lib to support mandatory Argon2id.
|
||||
|
||||
* Fix for the cryptsetup-reencrypt static build if pwquality is enabled.
|
||||
|
||||
* Update LUKS1 standard doc (https links in the bibliography).
|
||||
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Offline re-encrypt tool LUKS2 support is currently limited.
|
||||
There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
(https://competitions.cr.yp.to/caesar.html) once these algorithms are
|
||||
available in the kernel (more on this later).
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
For the GCM, nonce collision is a fatal problem.
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated soon in favor
|
||||
of python bindings to the libblockdev library (that can already handle LUKS1
|
||||
devices).
|
||||
93
docs/v2.0.2-ReleaseNotes
Normal file
93
docs/v2.0.2-ReleaseNotes
Normal file
@@ -0,0 +1,93 @@
|
||||
Cryptsetup 2.0.2 Release Notes
|
||||
==============================
|
||||
Stable and bug-fix release with experimental features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix a regression in early detection of inactive keyslot for luksKillSlot.
|
||||
It tried to ask for passphrase even for already erased keyslot.
|
||||
|
||||
* Fix a regression in loopaesOpen processing for keyfile on standard input.
|
||||
Use of "-" argument was not working properly.
|
||||
|
||||
* Add LUKS2 specific options for cryptsetup-reencrypt.
|
||||
Tokens and persistent flags are now transferred during reencryption;
|
||||
change of PBKDF keyslot parameters is now supported and allows
|
||||
to set precalculated values (no benchmarks).
|
||||
|
||||
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags
|
||||
combination. Persistent flags are now stored only if the device was
|
||||
successfully activated with the specified flags.
|
||||
|
||||
* Fix integritysetup format after recent Linux kernel changes that
|
||||
requires to setup key for HMAC in all cases.
|
||||
Previously integritysetup allowed HMAC with zero key that behaves
|
||||
like a plain hash.
|
||||
|
||||
* Fix VeraCrypt PIM handling that modified internal iteration counts
|
||||
even for subsequent activations. The PIM count is no longer printed
|
||||
in debug log as it is sensitive information.
|
||||
Also, the code now skips legacy TrueCrypt algorithms if a PIM
|
||||
is specified (they cannot be used with PIM anyway).
|
||||
|
||||
* PBKDF values cannot be set (even with force parameters) below
|
||||
hardcoded minimums. For PBKDF2 is it 1000 iterations, for Argon2
|
||||
it is 4 iterations and 32 KiB of memory cost.
|
||||
|
||||
* Introduce new crypt_token_is_assigned() API function for reporting
|
||||
the binding between token and keyslots.
|
||||
|
||||
* Allow crypt_token_json_set() API function to create internal token types.
|
||||
Do not allow unknown fields in internal token objects.
|
||||
|
||||
* Print message in cryptsetup that about was aborted if a user did not
|
||||
answer YES in a query.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS, as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
121
docs/v2.0.3-ReleaseNotes
Normal file
121
docs/v2.0.3-ReleaseNotes
Normal file
@@ -0,0 +1,121 @@
|
||||
Cryptsetup 2.0.3 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Expose interface to unbound LUKS2 keyslots.
|
||||
Unbound LUKS2 keyslot allows storing a key material that is independent
|
||||
of master volume key (it is not bound to encrypted data segment).
|
||||
|
||||
* New API extensions for unbound keyslots (LUKS2 only)
|
||||
crypt_keyslot_get_key_size() and crypt_volume_key_get()
|
||||
These functions allow to get key and key size for unbound keyslots.
|
||||
|
||||
* New enum value CRYPT_SLOT_UNBOUND for keyslot status (LUKS2 only).
|
||||
|
||||
* Add --unbound keyslot option to the cryptsetup luksAddKey command.
|
||||
|
||||
* Add crypt_get_active_integrity_failures() call to get integrity
|
||||
failure count for dm-integrity devices.
|
||||
|
||||
* Add crypt_get_pbkdf_default() function to get per-type PBKDF default
|
||||
setting.
|
||||
|
||||
* Add new flag to crypt_keyslot_add_by_key() to force update device
|
||||
volume key. This call is mainly intended for a wrapped key change.
|
||||
|
||||
* Allow volume key store in a file with cryptsetup.
|
||||
The --dump-master-key together with --master-key-file allows cryptsetup
|
||||
to store the binary volume key to a file instead of standard output.
|
||||
|
||||
* Add support detached header for cryptsetup-reencrypt command.
|
||||
|
||||
* Fix VeraCrypt PIM handling - use proper iterations count formula
|
||||
for PBKDF2-SHA512 and PBKDF2-Whirlpool used in system volumes.
|
||||
|
||||
* Fix cryptsetup tcryptDump for VeraCrypt PIM (support --veracrypt-pim).
|
||||
|
||||
* Add --with-default-luks-format configure time option.
|
||||
(Option to override default LUKS format version.)
|
||||
|
||||
* Fix LUKS version conversion for detached (and trimmed) LUKS headers.
|
||||
|
||||
* Add luksConvertKey cryptsetup command that converts specific keyslot
|
||||
from one PBKDF to another.
|
||||
|
||||
* Do not allow conversion to LUKS2 if LUKSMETA (external tool metadata)
|
||||
header is detected.
|
||||
|
||||
* More cleanup and hardening of LUKS2 keyslot specific validation options.
|
||||
Add more checks for cipher validity before writing metadata on-disk.
|
||||
|
||||
* Do not allow LUKS1 version downconversion if the header contains tokens.
|
||||
|
||||
* Add "paes" family ciphers (AES wrapped key scheme for mainframes)
|
||||
to allowed ciphers.
|
||||
Specific wrapped ley configuration logic must be done by 3rd party tool,
|
||||
LUKS2 stores only keyslot material and allow activation of the device.
|
||||
|
||||
* Add support for --check-at-most-once option (kernel 4.17) to veritysetup.
|
||||
This flag can be dangerous; if you can control underlying device
|
||||
(you can change its content after it was verified) it will no longer
|
||||
prevent reading tampered data and also it does not prevent silent
|
||||
data corruptions that appear after the block was once read.
|
||||
|
||||
* Fix return code (EPERM instead of EINVAL) and retry count for bad
|
||||
passphrase on non-tty input.
|
||||
|
||||
* Enable support for FEC decoding in veritysetup to check dm-verity devices
|
||||
with additional Reed-Solomon code in userspace (verify command).
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples (planned for 2.0.4).
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS, as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases/tag/2.17-1 that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
119
docs/v2.0.4-ReleaseNotes
Normal file
119
docs/v2.0.4-ReleaseNotes
Normal file
@@ -0,0 +1,119 @@
|
||||
Cryptsetup 2.0.4 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.3
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Use the libblkid (blockid) library to detect foreign signatures
|
||||
on a device before LUKS format and LUKS2 auto-recovery.
|
||||
|
||||
This change fixes an unexpected recovery using the secondary
|
||||
LUKS2 header after a device was already overwritten with
|
||||
another format (filesystem or LVM physical volume).
|
||||
|
||||
LUKS2 will not recreate a primary header if it detects a valid
|
||||
foreign signature. In this situation, a user must always
|
||||
use cryptsetup repair command for the recovery.
|
||||
|
||||
Note that libcryptsetup and utilities are now linked to libblkid
|
||||
as a new dependence.
|
||||
|
||||
To compile code without blockid support (strongly discouraged),
|
||||
use --disable-blkid configure switch.
|
||||
|
||||
* Add prompt for format and repair actions in cryptsetup and
|
||||
integritysetup if foreign signatures are detected on the device
|
||||
through the blockid library.
|
||||
|
||||
After the confirmation, all known signatures are then wiped as
|
||||
part of the format or repair procedure.
|
||||
|
||||
* Print consistent verbose message about keyslot and token numbers.
|
||||
For keyslot actions: Key slot <number> unlocked/created/removed.
|
||||
For token actions: Token <number> created/removed.
|
||||
|
||||
* Print error, if a non-existent token is tried to be removed.
|
||||
|
||||
* Add support for LUKS2 token definition export and import.
|
||||
|
||||
The token command now can export/import customized token JSON file
|
||||
directly from command line. See the man page for more details.
|
||||
|
||||
* Add support for new dm-integrity superblock version 2.
|
||||
|
||||
* Add an error message when nothing was read from a key file.
|
||||
|
||||
* Update cryptsetup man pages, including --type option usage.
|
||||
|
||||
* Add a snapshot of LUKS2 format specification to documentation
|
||||
and accordingly fix supported secondary header offsets.
|
||||
|
||||
* Add bundled optimized Argon2 SSE (X86_64 platform) code.
|
||||
|
||||
If the bundled Argon2 code is used and the new configure switch
|
||||
--enable-internal-sse-argon2 option is present, and compiler flags
|
||||
support required optimization, the code will try to use optimized
|
||||
and faster variant.
|
||||
|
||||
Always use the shared library (--enable-libargon2) if possible.
|
||||
|
||||
This option was added because an enterprise distribution
|
||||
rejected to support the shared Argon2 library and native support
|
||||
in generic cryptographic libraries is not ready yet.
|
||||
|
||||
* Fix compilation with crypto backend for LibreSSL >= 2.7.0.
|
||||
LibreSSL introduced OpenSSL 1.1.x API functions, so compatibility
|
||||
wrapper must be commented out.
|
||||
|
||||
* Fix on-disk header size calculation for LUKS2 format if a specific
|
||||
data alignment is requested. Until now, the code used default size
|
||||
that could be wrong for converted devices.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS (in kernel 4.18), as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
|
||||
102
docs/v2.0.5-ReleaseNotes
Normal file
102
docs/v2.0.5-ReleaseNotes
Normal file
@@ -0,0 +1,102 @@
|
||||
Cryptsetup 2.0.5 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.4
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Wipe full header areas (including unused) during LUKS format.
|
||||
|
||||
Since this version, the whole area up to the data offset is zeroed,
|
||||
and subsequently, all keyslots areas are wiped with random data.
|
||||
This ensures that no remaining old data remains in the LUKS header
|
||||
areas, but it could slow down format operation on some devices.
|
||||
Previously only first 4k (or 32k for LUKS2) and the used keyslot
|
||||
was overwritten in the format operation.
|
||||
|
||||
* Several fixes to error messages that were unintentionally replaced
|
||||
in previous versions with a silent exit code.
|
||||
More descriptive error messages were added, including error
|
||||
messages if
|
||||
- a device is unusable (not a block device, no access, etc.),
|
||||
- a LUKS device is not detected,
|
||||
- LUKS header load code detects unsupported version,
|
||||
- a keyslot decryption fails (also happens in the cipher check),
|
||||
- converting an inactive keyslot.
|
||||
|
||||
* Device activation fails if data area overlaps with LUKS header.
|
||||
|
||||
* Code now uses explicit_bzero to wipe memory if available
|
||||
(instead of own implementation).
|
||||
|
||||
* Additional VeraCrypt modes are now supported, including Camellia
|
||||
and Kuznyechik symmetric ciphers (and cipher chains) and Streebog
|
||||
hash function. These were introduced in a recent VeraCrypt upstream.
|
||||
|
||||
Note that Kuznyechik requires out-of-tree kernel module and
|
||||
Streebog hash function is available only with the gcrypt cryptographic
|
||||
backend for now.
|
||||
|
||||
* Fixes static build for integritysetup if the pwquality library is used.
|
||||
|
||||
* Allows passphrase change for unbound keyslots.
|
||||
|
||||
* Fixes removed keyslot number in verbose message for luksKillSlot,
|
||||
luksRemoveKey and erase command.
|
||||
|
||||
* Adds blkid scan when attempting to open a plain device and warn the user
|
||||
about existing device signatures in a ciphertext device.
|
||||
|
||||
* Remove LUKS header signature if luksFormat fails to add the first keyslot.
|
||||
|
||||
* Remove O_SYNC from device open and use fsync() to speed up
|
||||
wipe operation considerably.
|
||||
|
||||
* Create --master-key-file in luksDump and fail if the file already exists.
|
||||
|
||||
* Fixes a bug when LUKS2 authenticated encryption with a detached header
|
||||
wiped the header device instead of dm-integrity data device area (causing
|
||||
unnecessary LUKS2 header auto recovery).
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption should use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
AEGIS and MORUS are already available in kernel 4.18.
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
Please note that authenticated encryption is still an experimental feature
|
||||
and can have performance problems for hish-speed devices and device
|
||||
with larger IO blocks (like RAID).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
97
docs/v2.0.6-ReleaseNotes
Normal file
97
docs/v2.0.6-ReleaseNotes
Normal file
@@ -0,0 +1,97 @@
|
||||
Cryptsetup 2.0.6 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
All users of cryptsetup 2.0.x should upgrade to this version.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.5
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix support of larger metadata areas in LUKS2 header.
|
||||
|
||||
This release properly supports all specified metadata areas, as documented
|
||||
in LUKS2 format description (see docs/on-disk-format-luks2.pdf in archive).
|
||||
|
||||
Currently, only default metadata area size is used (in format or convert).
|
||||
Later cryptsetup versions will allow increasing this metadata area size.
|
||||
|
||||
* If AEAD (authenticated encryption) is used, cryptsetup now tries to check
|
||||
if the requested AEAD algorithm with specified key size is available
|
||||
in kernel crypto API.
|
||||
This change avoids formatting a device that cannot be later activated.
|
||||
|
||||
For this function, the kernel must be compiled with the
|
||||
CONFIG_CRYPTO_USER_API_AEAD option enabled.
|
||||
Note that kernel user crypto API options (CONFIG_CRYPTO_USER_API and
|
||||
CONFIG_CRYPTO_USER_API_SKCIPHER) are already mandatory for LUKS2.
|
||||
|
||||
* Fix setting of integrity no-journal flag.
|
||||
Now you can store this flag to metadata using --persistent option.
|
||||
|
||||
* Fix cryptsetup-reencrypt to not keep temporary reencryption headers
|
||||
if interrupted during initial password prompt.
|
||||
|
||||
* Adds early check to plain and LUKS2 formats to disallow device format
|
||||
if device size is not aligned to requested sector size.
|
||||
Previously it was possible, and the device was rejected to activate by
|
||||
kernel later.
|
||||
|
||||
* Fix checking of hash algorithms availability for PBKDF early.
|
||||
Previously LUKS2 format allowed non-existent hash algorithm with
|
||||
invalid keyslot preventing the device from activation.
|
||||
|
||||
* Allow Adiantum cipher construction (a non-authenticated length-preserving
|
||||
fast encryption scheme), so it can be used both for data encryption and
|
||||
keyslot encryption in LUKS1/2 devices.
|
||||
|
||||
For benchmark, use:
|
||||
# cryptsetup benchmark -c xchacha12,aes-adiantum
|
||||
# cryptsetup benchmark -c xchacha20,aes-adiantum
|
||||
|
||||
For LUKS format:
|
||||
# cryptsetup luksFormat -c xchacha20,aes-adiantum-plain64 -s 256 <device>
|
||||
|
||||
The support for Adiantum will be merged in Linux kernel 4.21.
|
||||
For more info see the paper https://eprint.iacr.org/2018/720.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption should use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
AEGIS and MORUS are already available in kernel 4.18.
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
Please note that authenticated encryption is still an experimental feature
|
||||
and can have performance problems for high-speed devices and device
|
||||
with larger IO blocks (like RAID).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
210
docs/v2.1.0-ReleaseNotes
Normal file
210
docs/v2.1.0-ReleaseNotes
Normal file
@@ -0,0 +1,210 @@
|
||||
Cryptsetup 2.1.0 Release Notes
|
||||
==============================
|
||||
Stable release with new features and bug fixes.
|
||||
|
||||
Cryptsetup 2.1 version uses a new on-disk LUKS2 format as the default
|
||||
LUKS format and increases default LUKS2 header size.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported forever
|
||||
as well as a traditional and fully backward compatible format.
|
||||
|
||||
When upgrading a stable distribution, please use configure option
|
||||
--with-default-luks-format=LUKS1 to maintain backward compatibility.
|
||||
|
||||
This release also switches to OpenSSL as a default cryptographic
|
||||
backend for LUKS header processing. Use --with-crypto_backend=gcrypt
|
||||
configure option if you need to preserve legacy libgcrypt backend.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or
|
||||
in production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.6
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* The default for cryptsetup LUKS format action is now LUKS2.
|
||||
You can use LUKS1 with cryptsetup option --type luks1.
|
||||
|
||||
* The default size of the LUKS2 header is increased to 16 MB.
|
||||
It includes metadata and the area used for binary keyslots;
|
||||
it means that LUKS header backup is now 16MB in size.
|
||||
|
||||
Note, that used keyslot area is much smaller, but this increase
|
||||
of reserved space allows implementation of later extensions
|
||||
(like online reencryption).
|
||||
It is fully compatible with older cryptsetup 2.0.x versions.
|
||||
If you require to create LUKS2 header with the same size as
|
||||
in the 2.0.x version, use --offset 8192 option for luksFormat
|
||||
(units are in 512-bytes sectors; see notes below).
|
||||
|
||||
* Cryptsetup now doubles LUKS default key size if XTS mode is used
|
||||
(XTS mode uses two internal keys). This does not apply if key size
|
||||
is explicitly specified on the command line and it does not apply
|
||||
for the plain mode.
|
||||
This fixes a confusion with AES and 256bit key in XTS mode where
|
||||
code used AES128 and not AES256 as often expected.
|
||||
|
||||
Also, the default keyslot encryption algorithm (if cannot be derived
|
||||
from data encryption algorithm) is now available as configure
|
||||
options --with-luks2-keyslot-cipher and --with-luks2-keyslot-keybits.
|
||||
The default is aes-xts-plain64 with 2 * 256-bits key.
|
||||
|
||||
* Default cryptographic backend used for LUKS header processing is now
|
||||
OpenSSL. For years, OpenSSL provided better performance for PBKDF.
|
||||
|
||||
NOTE: Cryptsetup/libcryptsetup supports several cryptographic
|
||||
library backends. The fully supported are libgcrypt, OpenSSL and
|
||||
kernel crypto API. FIPS mode extensions are maintained only for
|
||||
libgcrypt and OpenSSL. Nettle and NSS are usable only for some
|
||||
subset of algorithms and cannot provide full backward compatibility.
|
||||
You can always switch to other backends by using a configure switch,
|
||||
for libgcrypt (compatibility for older distributions) use:
|
||||
--with-crypto_backend=gcrypt
|
||||
|
||||
* The Python bindings are no longer supported and the code was removed
|
||||
from cryptsetup distribution. Please use the libblockdev project
|
||||
that already covers most of the libcryptsetup functionality
|
||||
including LUKS2.
|
||||
|
||||
* Cryptsetup now allows using --offset option also for luksFormat.
|
||||
It means that the specified offset value is used for data offset.
|
||||
LUKS2 header areas are automatically adjusted according to this value.
|
||||
(Note units are in 512-byte sectors due to the previous definition
|
||||
of this option in plain mode.)
|
||||
This option can replace --align-payload with absolute alignment value.
|
||||
|
||||
* Cryptsetup now supports new refresh action (that is the alias for
|
||||
"open --refresh").
|
||||
It allows changes of parameters for an active device (like root
|
||||
device mapping), for example, it can enable or disable TRIM support
|
||||
on-the-fly.
|
||||
It is supported for LUKS1, LUKS2, plain and loop-AES devices.
|
||||
|
||||
* Integritysetup now supports mode with detached data device through
|
||||
new --data-device option.
|
||||
Since kernel 4.18 there is a possibility to specify external data
|
||||
device for dm-integrity that stores all integrity tags.
|
||||
|
||||
* Integritysetup now supports automatic integrity recalculation
|
||||
through new --integrity-recalculate option.
|
||||
Linux kernel since version 4.18 supports automatic background
|
||||
recalculation of integrity tags for dm-integrity.
|
||||
|
||||
Other changes and fixes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix for crypt_wipe call to allocate space if the header is backed
|
||||
by a file. This means that if you use detached header file, it will
|
||||
now have always the full size after luksFormat, even if only
|
||||
a few keyslots are used.
|
||||
|
||||
* Fixes to offline cryptsetup-reencrypt to preserve LUKS2 keyslots
|
||||
area sizes after reencryption and fixes for some other issues when
|
||||
creating temporary reencryption headers.
|
||||
|
||||
* Added some FIPS mode workarounds. We cannot (yet) use Argon2 in
|
||||
FIPS mode, libcryptsetup now fallbacks to use PBKDF2 in FIPS mode.
|
||||
|
||||
* Rejects conversion to LUKS1 if PBKDF2 hash algorithms
|
||||
in keyslots differ.
|
||||
|
||||
* The hash setting on command line now applies also to LUKS2 PBKDF2
|
||||
digest. In previous versions, the LUKS2 key digest used PBKDF2-SHA256
|
||||
(except for converted headers).
|
||||
|
||||
* Allow LUKS2 keyslots area to increase if data offset allows it.
|
||||
Cryptsetup can fine-tune LUKS2 metadata area sizes through
|
||||
--luks2-metadata-size=BYTES and --luks2-keyslots-size=BYTES.
|
||||
Please DO NOT use these low-level options until you need it for
|
||||
some very specific additional feature.
|
||||
Also, the code now prints these LUKS2 header area sizes in dump
|
||||
command.
|
||||
|
||||
* For LUKS2, keyslot can use different encryption that data with
|
||||
new options --keyslot-key-size=BITS and --keyslot-cipher=STRING
|
||||
in all commands that create new LUKS keyslot.
|
||||
Please DO NOT use these low-level options until you need it for
|
||||
some very specific additional feature.
|
||||
|
||||
* Code now avoids data flush when reading device status through
|
||||
device-mapper.
|
||||
|
||||
* The Nettle crypto backend and the userspace kernel crypto API
|
||||
backend were enhanced to allow more available hash functions
|
||||
(like SHA3 variants).
|
||||
|
||||
* Upstream code now does not require libgcrypt-devel
|
||||
for autoconfigure, because OpenSSL is the default.
|
||||
The libgcrypt does not use standard pkgconfig detection and
|
||||
requires specific macro (part of libgcrypt development files)
|
||||
to be always present during autoconfigure.
|
||||
With other crypto backends, like OpenSSL, this makes no sense,
|
||||
so this part of autoconfigure is now optional.
|
||||
|
||||
* Cryptsetup now understands new --debug-json option that allows
|
||||
an additional dump of some JSON information. These are no longer
|
||||
present in standard debug output because it could contain some
|
||||
specific LUKS header parameters.
|
||||
|
||||
* The luksDump contains the hash algorithm used in Anti-Forensic
|
||||
function.
|
||||
|
||||
* All debug messages are now sent through configured log callback
|
||||
functions, so an application can easily use own debug messages
|
||||
handling. In previous versions debug messages were printed directly
|
||||
to standard output.)
|
||||
|
||||
Libcryptsetup API additions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These new calls are now exported, for details see libcryptsetup.h:
|
||||
|
||||
* crypt_init_data_device
|
||||
* crypt_get_metadata_device_name
|
||||
functions to init devices with separate metadata and data device
|
||||
before a format function is called.
|
||||
|
||||
* crypt_set_data_offset
|
||||
sets the data offset for LUKS to the specified value
|
||||
in 512-byte sectors.
|
||||
It should replace alignment calculation in LUKS param structures.
|
||||
|
||||
* crypt_get_metadata_size
|
||||
* crypt_set_metadata_size
|
||||
allows to set/get area sizes in LUKS header
|
||||
(according to specification).
|
||||
|
||||
* crypt_get_default_type
|
||||
get default compiled-in LUKS type (version).
|
||||
|
||||
* crypt_get_pbkdf_type_params
|
||||
allows to get compiled-in PBKDF parameters.
|
||||
|
||||
* crypt_keyslot_set_encryption
|
||||
* crypt_keyslot_get_encryption
|
||||
allows to set/get per-keyslot encryption algorithm for LUKS2.
|
||||
|
||||
* crypt_keyslot_get_pbkdf
|
||||
allows to get PBKDF parameters per-keyslot.
|
||||
|
||||
and these new defines:
|
||||
* CRYPT_LOG_DEBUG_JSON (message type for JSON debug)
|
||||
* CRYPT_DEBUG_JSON (log level for JSON debug)
|
||||
* CRYPT_ACTIVATE_RECALCULATE (dm-integrity recalculate flag)
|
||||
* CRYPT_ACTIVATE_REFRESH (new open with refresh flag)
|
||||
|
||||
All existing API calls should remain backward compatible.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Optional authenticated encryption is still an experimental feature
|
||||
and can have performance problems for high-speed devices and device
|
||||
with larger IO blocks (like RAID).
|
||||
|
||||
* Authenticated encryption does not use encryption for a dm-integrity
|
||||
journal. While it does not influence data confidentiality or
|
||||
integrity protection, an attacker can get some more information
|
||||
from data journal or cause that system will corrupt sectors after
|
||||
journal replay. (That corruption will be detected though.)
|
||||
|
||||
* The LUKS2 metadata area increase is mainly needed for the new online
|
||||
reencryption as the major feature for the next release.
|
||||
279
docs/v2.2.0-ReleaseNotes
Normal file
279
docs/v2.2.0-ReleaseNotes
Normal file
@@ -0,0 +1,279 @@
|
||||
Cryptsetup 2.2.0 Release Notes
|
||||
==============================
|
||||
Stable release with new experimental features and bug fixes.
|
||||
|
||||
Cryptsetup 2.2 version introduces a new LUKS2 online reencryption
|
||||
extension that allows reencryption of mounted LUKS2 devices
|
||||
(device in use) in the background.
|
||||
|
||||
Online reencryption is a complex feature. Please be sure you
|
||||
have a full data backup before using this feature.
|
||||
|
||||
Changes since version 2.1.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
LUKS2 online reencryption
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The reencryption is intended to provide a reliable way to change
|
||||
volume key or an algorithm change while the encrypted device is still
|
||||
in use.
|
||||
|
||||
It is based on userspace-only approach (no kernel changes needed)
|
||||
that uses the device-mapper subsystem to remap active devices on-the-fly
|
||||
dynamically. The device is split into several segments (encrypted by old
|
||||
key, new key and so-called hotzone, where reencryption is actively running).
|
||||
|
||||
The flexible LUKS2 metadata format is used to store intermediate states
|
||||
(segment mappings) and both version of keyslots (old and new keys).
|
||||
Also, it provides a binary area (in the unused keyslot area space)
|
||||
to provide recovery metadata in the case of unexpected failure during
|
||||
reencryption. LUKS2 header is during the reencryption marked with
|
||||
"online-reencryption" keyword. After the reencryption is finished,
|
||||
this keyword is removed, and the device is backward compatible with all
|
||||
older cryptsetup tools (that support LUKS2).
|
||||
|
||||
The recovery supports three resilience modes:
|
||||
|
||||
- checksum: default mode, where individual checksums of ciphertext hotzone
|
||||
sectors are stored, so the recovery process can detect which sectors were
|
||||
already reencrypted. It requires that the device sector write is atomic.
|
||||
|
||||
- journal: the hotzone is journaled in the binary area
|
||||
(so the data are written twice)
|
||||
|
||||
- none: performance mode; there is no protection
|
||||
(similar to old offline reencryption)
|
||||
|
||||
These resilience modes are not available if reencryption uses data shift.
|
||||
|
||||
Note: until we have full documentation (both of the process and metadata),
|
||||
please refer to Ondrej's slides (some slight details are no longer relevant)
|
||||
https://okozina.fedorapeople.org/online-disk-reencryption-with-luks2-compact.pdf
|
||||
|
||||
The offline reencryption tool (cryptsetup-reencrypt) is still supported
|
||||
for both LUKS1 and LUKS2 format.
|
||||
|
||||
Cryptsetup examples for reencryption
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The reencryption feature is integrated directly into cryptsetup utility
|
||||
as the new "reencrypt" action (command).
|
||||
|
||||
There are three basic modes - to perform reencryption (change of already
|
||||
existing LUKS2 device), to add encryption to plaintext device and to remove
|
||||
encryption from a device (decryption).
|
||||
|
||||
In all cases, if existing LUKS2 metadata contains information about
|
||||
the ongoing reencryption process, following reencrypt command continues
|
||||
with the ongoing reencryption process until it is finished.
|
||||
|
||||
You can activate a device with ongoing reencryption as the standard LUKS2
|
||||
device, but the reencryption process will not continue until the cryptsetup
|
||||
reencrypt command is issued.
|
||||
|
||||
|
||||
1) Reencryption
|
||||
~~~~~~~~~~~~~~~
|
||||
This mode is intended to change any attribute of the data encryption
|
||||
(change of the volume key, algorithm or sector size).
|
||||
Note that authenticated encryption is not yet supported.
|
||||
|
||||
You can start the reencryption process by specifying a LUKS2 device or with
|
||||
a detached LUKS2 header.
|
||||
The code should automatically recognize if the device is in use (and if it
|
||||
should use online mode of reencryption).
|
||||
|
||||
If you do not specify parameters, only volume key is changed
|
||||
(a new random key is generated).
|
||||
|
||||
# cryptsetup reencrypt <device> [--header <hdr>]
|
||||
|
||||
You can also start reencryption using active mapped device name:
|
||||
# cryptsetup reencrypt --active-name <name>
|
||||
|
||||
You can also specify the resilience mode (none, checksum, journal) with
|
||||
--resilience=<mode> option, for checksum mode also the hash algorithm with
|
||||
--resilience-hash=<alg> (only hash algorithms supported by cryptographic
|
||||
backend are available).
|
||||
|
||||
The maximal size of reencryption hotzone can be limited by
|
||||
--hotzone-size=<size> option and applies to all reencryption modes.
|
||||
Note that for checksum and journal mode hotzone size is also limited
|
||||
by available space in binary keyslot area.
|
||||
|
||||
2) Encryption
|
||||
~~~~~~~~~~~~~
|
||||
This mode provides a way to encrypt a plaintext device to LUKS2 format.
|
||||
This option requires reduction of device size (for LUKS2 header) or new
|
||||
detached header.
|
||||
|
||||
# cryptsetup reencrypt <device> --encrypt --reduce-device-size <size>
|
||||
|
||||
Or with detached header:
|
||||
# cryptsetup reencrypt <device> --encrypt --header <hdr>
|
||||
|
||||
3) Decryption
|
||||
~~~~~~~~~~~~~
|
||||
This mode provides the removal of existing LUKS2 encryption and replacing
|
||||
a device with plaintext content only.
|
||||
For now, we support only decryption with a detached header.
|
||||
|
||||
# cryptsetup reencrypt <device> --decrypt --header <hdr>
|
||||
|
||||
For all three modes, you can split the process to metadata initialization
|
||||
(prepare keyslots and segments but do not run reencryption yet) and the data
|
||||
reencryption step by using --init-only option.
|
||||
|
||||
Prepares metadata:
|
||||
# cryptsetup reencrypt --init-only <parameters>
|
||||
|
||||
Starts the data processing:
|
||||
# cryptsetup reencrypt <device>
|
||||
|
||||
Please note, that due to the Linux kernel limitation, the encryption or
|
||||
decryption process cannot be run entirely online - there must be at least
|
||||
short offline window where operation adds/removes device-mapper crypt (LUKS2) layer.
|
||||
This step should also include modification of /etc/crypttab and fstab UUIDs,
|
||||
but it is out of the scope of cryptsetup tools.
|
||||
|
||||
Limitations
|
||||
~~~~~~~~~~~
|
||||
Most of these limitations will be (hopefully) fixed in next versions.
|
||||
|
||||
* Only one active keyslot is supported (all old keyslots will be removed
|
||||
after reencryption).
|
||||
|
||||
* Only block devices are now supported as parameters. As a workaround
|
||||
for images in a file, please explicitly map a loop device over the image
|
||||
and use the loop device as the parameter.
|
||||
|
||||
* Devices with authenticated encryption are not supported. (Later it will
|
||||
be limited by the fixed per-sector metadata, per-sector metadata size
|
||||
cannot be changed without a new device format operation.)
|
||||
|
||||
* The reencryption uses userspace crypto library, with fallback to
|
||||
the kernel (if available). There can be some specific configurations
|
||||
where the fallback does not provide optimal performance.
|
||||
|
||||
* There are no translations of error messages until the final release
|
||||
(some messages can be rephrased as well).
|
||||
|
||||
* The repair command is not finished; the recovery of interrupted
|
||||
reencryption is made automatically on the first device activation.
|
||||
|
||||
* Reencryption triggers too many udev scans on metadata updates (on closing
|
||||
write enabled file descriptors). This has a negative performance impact on the whole
|
||||
reencryption and generates excessive I/O load on the system.
|
||||
|
||||
New libcryptsetup reencryption API
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The libcryptsetup contains new API calls that are used to setup and
|
||||
run the reencryption.
|
||||
|
||||
Note that there can be some changes in API implementation of these functions
|
||||
and/or some new function can be introduced in final cryptsetup 2.2 release.
|
||||
|
||||
New API symbols (see documentation in libcryptsetup.h)
|
||||
* struct crypt_params_reencrypt - reencryption parameters
|
||||
|
||||
* crypt_reencrypt_init_by_passphrase
|
||||
* crypt_reencrypt_init_by_keyring
|
||||
- function to configure LUKS2 metadata for reencryption;
|
||||
if metadata already exists, it configures the context from this metadata
|
||||
|
||||
* crypt_reencrypt
|
||||
- run the reencryption process (processing the data)
|
||||
- the optional callback function can be used to interrupt the reencryption
|
||||
or report the progress.
|
||||
|
||||
* crypt_reencrypt_status
|
||||
- function to query LUKS2 metadata about the reencryption state
|
||||
|
||||
Other changes and fixes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Add optional global serialization lock for memory hard PBKDF.
|
||||
(The --serialize-memory-hard-pbkdf option in cryptsetup and
|
||||
CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF in activation flag.)
|
||||
|
||||
This is an "ugly" optional workaround for a situation when multiple devices
|
||||
are being activated in parallel (like systemd crypttab activation).
|
||||
The system instead of returning ENOMEM (no memory available) starts
|
||||
out-of-memory (OOM) killer to kill processes randomly.
|
||||
|
||||
Until we find a reliable way how to work with memory-hard function
|
||||
in these situations, cryptsetup provide a way how to serialize memory-hard
|
||||
unlocking among parallel cryptsetup instances to workaround this problem.
|
||||
This flag is intended to be used only in very specific situations,
|
||||
never use it directly :-)
|
||||
|
||||
* Abort conversion to LUKS1 with incompatible sector size that is
|
||||
not supported in LUKS1.
|
||||
|
||||
* Report error (-ENOENT) if no LUKS keyslots are available. User can now
|
||||
distinguish between a wrong passphrase and no keyslot available.
|
||||
|
||||
* Fix a possible segfault in detached header handling (double free).
|
||||
|
||||
* Add integritysetup support for bitmap mode introduced in Linux kernel 5.2.
|
||||
Integritysetup now supports --integrity-bitmap-mode option and
|
||||
--bitmap-sector-per-bit and --bitmap-flush-time commandline options.
|
||||
|
||||
In the bitmap operation mode, if a bit in the bitmap is 1, the corresponding
|
||||
region's data and integrity tags are not synchronized - if the machine
|
||||
crashes, the unsynchronized regions will be recalculated.
|
||||
The bitmap mode is faster than the journal mode because we don't have
|
||||
to write the data twice, but it is also less reliable, because if data
|
||||
corruption happens when the machine crashes, it may not be detected.
|
||||
This can be used only for standalone devices, not with dm-crypt.
|
||||
|
||||
* The libcryptsetup now keeps all file descriptors to underlying device
|
||||
open during the whole lifetime of crypt device context to avoid excessive
|
||||
scanning in udev (udev run scan on every descriptor close).
|
||||
|
||||
* The luksDump command now prints more info for reencryption keyslot
|
||||
(when a device is in-reencryption).
|
||||
|
||||
* New --device-size parameter is supported for LUKS2 reencryption.
|
||||
It may be used to encrypt/reencrypt only the initial part of the data
|
||||
device if the user is aware that the rest of the device is empty.
|
||||
|
||||
Note: This change causes API break since the last rc0 release
|
||||
(crypt_params_reencrypt structure contains additional field).
|
||||
|
||||
* New --resume-only parameter is supported for LUKS2 reencryption.
|
||||
This flag resumes reencryption process if it exists (not starting
|
||||
new reencryption).
|
||||
|
||||
* The repair command now tries LUKS2 reencryption recovery if needed.
|
||||
|
||||
* If reencryption device is a file image, an interactive dialog now
|
||||
asks if reencryption should be run safely in offline mode
|
||||
(if autodetection of active devices failed).
|
||||
|
||||
* Fix activation through a token where dm-crypt volume key was not
|
||||
set through keyring (but using old device-mapper table parameter mode).
|
||||
|
||||
* Online reencryption can now retain all keyslots (if all passphrases
|
||||
are provided). Note that keyslot numbers will change in this case.
|
||||
|
||||
* Allow volume key file to be used if no LUKS2 keyslots are present.
|
||||
If all keyslots are removed, LUKS2 has no longer information about
|
||||
the volume key size (there is only key digest present).
|
||||
Please use --key-size option to open the device or add a new keyslot
|
||||
in these cases.
|
||||
|
||||
* Print a warning if online reencrypt is called over LUKS1 (not supported).
|
||||
|
||||
* Fix TCRYPT KDF failure in FIPS mode.
|
||||
Some crypto backends support plain hash in FIPS mode but not for PBKDF2.
|
||||
|
||||
* Remove FIPS mode restriction for crypt_volume_key_get.
|
||||
It is an application responsibility to use this API in the proper context.
|
||||
|
||||
* Reduce keyslots area size in luksFormat when the header device is too small.
|
||||
Unless user explicitly asks for keyslots areas size (either via
|
||||
--luks2-keyslots-size or --offset) reduce keyslots size so that it fits
|
||||
in metadata device.
|
||||
|
||||
* Make resize action accept --device-size parameter (supports units suffix).
|
||||
36
docs/v2.2.1-ReleaseNotes
Normal file
36
docs/v2.2.1-ReleaseNotes
Normal file
@@ -0,0 +1,36 @@
|
||||
Cryptsetup 2.2.1 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
|
||||
This version contains a fix for a possible data corruption bug
|
||||
on 32-bit platforms.
|
||||
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
|
||||
|
||||
Changes since version 2.2.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix possible data length and IV offset overflow on 32bit architectures.
|
||||
Other 64-bit architectures are not affected.
|
||||
|
||||
The flawed helper function prototypes (introduced in version 2.1.0) used
|
||||
size_t type, that is 32-bit integer on 32-bit systems.
|
||||
This patch fixes the problem to properly use 64-bit types.
|
||||
|
||||
If the offset parameter addresses devices larger than 2TB, the value
|
||||
overflows and stores incorrect information in the metadata.
|
||||
For example, integrity device is smaller than expected size if used
|
||||
over large disk on 32-bit architecture.
|
||||
|
||||
This issue is not present with the standard LUKS1/LUKS2 devices without
|
||||
integrity extensions.
|
||||
|
||||
* Fix a regression in TrueCrypt/VeraCrypt system partition activation.
|
||||
|
||||
* Reinstate missing backing file hint for loop device.
|
||||
|
||||
If the encrypted device is backed by a file (loopback), cryptsetup now
|
||||
shows the path to the backing file in passphrase query (as in 1.x version).
|
||||
|
||||
* LUKS2 reencryption block size is now aligned to reported optimal IO size.
|
||||
This change eliminates possible non-aligned device warnings in kernel log
|
||||
during reencryption.
|
||||
56
docs/v2.2.2-ReleaseNotes
Normal file
56
docs/v2.2.2-ReleaseNotes
Normal file
@@ -0,0 +1,56 @@
|
||||
Cryptsetup 2.2.2 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
|
||||
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
|
||||
|
||||
Changes since version 2.2.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Print error message if a keyslot open failed for a different reason
|
||||
than wrong passwords (for example there is not enough memory).
|
||||
Only an exit code was present in this case.
|
||||
|
||||
* The progress function switches unit sizes (B/s to GiB/s) according
|
||||
to the actual speed. Also, it properly calculates speed in the case
|
||||
of a resumed reencryption operation.
|
||||
|
||||
* The --version now supports short -V short option and better handles
|
||||
common option priorities.
|
||||
|
||||
* If cryptsetup wipes signatures during format actions through blkid,
|
||||
it also prints signature device offsets.
|
||||
|
||||
* Compilation now properly uses LTLIBINTL gettext setting in Makefiles.
|
||||
|
||||
* Device-mapper backend now supports new DM_GET_TARGET_VERSION ioctl
|
||||
(available since Linux kernel 5.4).
|
||||
This should help to detect some kernel/userspace incompatibilities
|
||||
earlier later after a failed device activation.
|
||||
|
||||
* Fixes LUKS2 reencryption on systems without kernel keyring.
|
||||
|
||||
* Fixes unlocking prompt for partitions mapped through loop devices
|
||||
(to properly show the backing device).
|
||||
|
||||
* For LUKS2 decryption, a device is now marked for deferred removal
|
||||
to be automatically deactivated.
|
||||
|
||||
* Reencryption now limits hotzone size to be maximal 1 GiB or 1/4
|
||||
system memory (if lower).
|
||||
|
||||
* Reencryption now retains activation flags during online reencryption.
|
||||
|
||||
* Reencryption now allows LUKS2 device to activate device right after
|
||||
LUKS2 encryption is initialized through optional active device name
|
||||
for cryptsetup reencrypt --encrypt command.
|
||||
This could help with automated encryption during boot.
|
||||
|
||||
NOTE: It means that part of the device is still not encrypted during
|
||||
activation. Use with care!
|
||||
|
||||
* Fixes failure in resize and plain format activation if activated device
|
||||
size was not aligned to underlying logical device size.
|
||||
|
||||
* Fixes conversion to LUKS2 format with detached header if a detached
|
||||
header size was smaller than the expected aligned LUKS1 header size.
|
||||
209
docs/v2.3.0-ReleaseNotes
Normal file
209
docs/v2.3.0-ReleaseNotes
Normal file
@@ -0,0 +1,209 @@
|
||||
Cryptsetup 2.3.0 Release Notes
|
||||
==============================
|
||||
Stable release with new experimental features and bug fixes.
|
||||
|
||||
Cryptsetup 2.3 version introduces support for BitLocker-compatible
|
||||
devices (BITLK format). This format is used in Windows systems,
|
||||
and in combination with a filesystem driver, cryptsetup now provides
|
||||
native read-write access to BitLocker Full Disk Encryption devices.
|
||||
|
||||
The BITLK implementation is based on publicly available information
|
||||
and it is an independent and opensource implementation that allows
|
||||
to access this proprietary disk encryption.
|
||||
|
||||
Changes since version 2.2.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* BITLK (Windows BitLocker compatible) device access
|
||||
|
||||
BITLK userspace implementation is based on the master thesis and code
|
||||
provided by Vojtech Trefny. Also, thanks to other opensource projects
|
||||
like libbde (that provide alternative approach to decode this format)
|
||||
we were able to verify cryptsetup implementation.
|
||||
|
||||
NOTE: Support for the BITLK device is EXPERIMENTAL and will require
|
||||
a lot of testing. If you get some error message (mainly unsupported
|
||||
metadata in the on-disk header), please help us by submitting an issue
|
||||
to cryptsetup project, so we can fix it. Thank you!
|
||||
|
||||
Cryptsetup supports BITLK activation through passphrase or recovery
|
||||
passphrase for existing devices (BitLocker and Bitlocker to Go).
|
||||
|
||||
Activation through TPM, SmartCard, or any other key protector
|
||||
is not supported. And in some situations, mainly for TPM bind to some
|
||||
PCR registers, it could be even impossible on Linux in the future.
|
||||
|
||||
All metadata (key protectors) are handled read-only, cryptsetup cannot
|
||||
create or modify them. Except for old devices (created in old Vista
|
||||
systems), all format variants should be recognized.
|
||||
|
||||
Data devices can be activated read-write (followed by mounting through
|
||||
the proper filesystem driver). To access filesystem on the decrypted device
|
||||
you need properly installed driver (vfat, NTFS or exFAT).
|
||||
|
||||
Foe AES-XTS, activation is supported on all recent Linux kernels.
|
||||
|
||||
For older AES-CBC encryption, Linux Kernel version 5.3 is required
|
||||
(support for special IV variant); for AES-CBC with Elephant diffuser,
|
||||
Linux Kernel 5.6 is required.
|
||||
|
||||
Please note that CBC variants are legacy, and we provide it only
|
||||
for backward compatibility (to be able to access old drives).
|
||||
|
||||
Cryptsetup command now supports the new "bitlk" format and implement dump,
|
||||
open, status, and close actions.
|
||||
|
||||
To activate a BITLK device, use
|
||||
|
||||
# cryptsetup open --type bitlk <device> <name>
|
||||
or with alias
|
||||
# cryptsetup bitlkOpen <device> <name>
|
||||
|
||||
Then with properly installed fs driver (usually NTFS, vfat or exFAT),
|
||||
you can mount the plaintext device /dev/mapper<name> device as a common
|
||||
filesystem.
|
||||
|
||||
To print metadata information about BITLK device, use
|
||||
# crypotsetup bitlkDump <device>
|
||||
|
||||
To print information about the active device, use
|
||||
# cryptsetup status <name>
|
||||
|
||||
Example (activation of disk image):
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# Recent blkid recognizes BitLocker device,just to verity
|
||||
# blkid bitlocker_xts_ntfs.img
|
||||
bitlocker_xts_ntfs.img: TYPE="BitLocker"
|
||||
|
||||
# Print visible metadata information (on-disk, form the image)
|
||||
# cryptsetup bitlkDump bitlocker_xts_ntfs.img
|
||||
Info for BITLK device bitlocker_xts_ntfs.img.
|
||||
Version: 2
|
||||
GUID: ...
|
||||
Created: Wed Oct 23 17:38:15 2019
|
||||
Description: DESKTOP-xxxxxxx E: 23.10.2019
|
||||
Cipher name: aes
|
||||
Cipher mode: xts-plain64
|
||||
Cipher key: 128 bits
|
||||
|
||||
Keyslots:
|
||||
0: VMK
|
||||
GUID: ...
|
||||
Protection: VMK protected with passphrase
|
||||
Salt: ...
|
||||
Key data size: 44 [bytes]
|
||||
1: VMK
|
||||
GUID: ...
|
||||
Protection: VMK protected with recovery passphrase
|
||||
Salt: ...
|
||||
Key data size: 44 [bytes]
|
||||
2: FVEK
|
||||
Key data size: 44 [bytes]
|
||||
|
||||
# Activation (recovery passphrase works the same as password)
|
||||
# cryptsetup bitlkOpen bitlocker_xts_ntfs.img test -v
|
||||
Enter passphrase for bitlocker_xts_ntfs.img:
|
||||
Command successful.
|
||||
|
||||
# Information about the active device
|
||||
# cryptsetup status test
|
||||
/dev/mapper/test is active.
|
||||
type: BITLK
|
||||
cipher: aes-xts-plain64
|
||||
keysize: 128 bits
|
||||
...
|
||||
|
||||
# Plaintext device should now contain decrypted NTFS filesystem
|
||||
# blkid /dev/mapper/test
|
||||
/dev/mapper/test: UUID="..." TYPE="ntfs"
|
||||
|
||||
# And can be mounted
|
||||
# mount /dev/mapper/test /mnt/tst
|
||||
|
||||
# Deactivation
|
||||
# umount /mnt/tst
|
||||
# cryptsetup close test
|
||||
|
||||
* Veritysetup now supports activation with additional PKCS7 signature
|
||||
of root hash through --root-hash-signature option.
|
||||
The signature uses an in-kernel trusted key to validate the signature
|
||||
of the root hash during activation. This option requires Linux kernel
|
||||
5.4 with DM_VERITY_VERIFY_ROOTHASH_SIG option.
|
||||
|
||||
Verity devices activated with signature now has a special flag
|
||||
(with signature) active in device status (veritysetup status <name>).
|
||||
|
||||
Usage:
|
||||
# veritysetup open <data_device> name <hash_device> <root_hash> \
|
||||
--root-hash-signature=<roothash_p7_sig_file>
|
||||
|
||||
* Integritysetup now calculates hash integrity size according to algorithm
|
||||
instead of requiring an explicit tag size.
|
||||
|
||||
Previously, when integritysetup formats a device with hash or
|
||||
HMAC integrity checksums, it required explicitly tag size entry from
|
||||
a user (or used default value).
|
||||
This led to confusion and unexpected shortened tag sizes.
|
||||
|
||||
Now, libcryptsetup calculates tag size according to real hash output.
|
||||
Tag size can also be specified, then it warns if these values differ.
|
||||
|
||||
* Integritysetup now supports fixed padding for dm-integrity devices.
|
||||
|
||||
There was an in-kernel bug that wasted a lot of space when using metadata
|
||||
areas for integrity-protected devices if a larger sector size than
|
||||
512 bytes was used.
|
||||
This problem affects both stand-alone dm-integrity and also LUKS2 with
|
||||
authenticated encryption and larger sector size.
|
||||
|
||||
The new extension to dm-integrity superblock is needed, so devices
|
||||
with the new optimal padding cannot be activated on older systems.
|
||||
|
||||
Integritysetup/Cryptsetup will use new padding automatically if it
|
||||
detects the proper kernel. To create a compatible device with
|
||||
the old padding, use --integrity-legacy-padding option.
|
||||
|
||||
* A lot of fixes to online LUKS2 reecryption.
|
||||
|
||||
* Add crypt_resume_by_volume_key() function to libcryptsetup.
|
||||
If a user has a volume key available, the LUKS device can be resumed
|
||||
directly using the provided volume key.
|
||||
No keyslot derivation is needed, only the key digest is checked.
|
||||
|
||||
* Implement active device suspend info.
|
||||
Add CRYPT_ACTIVATE_SUSPENDED bit to crypt_get_active_device() flags
|
||||
that informs the caller that device is suspended (luksSuspend).
|
||||
|
||||
* Allow --test-passphrase for a detached header.
|
||||
Before this fix, we required a data device specified on the command
|
||||
line even though it was not necessary for the passphrase check.
|
||||
|
||||
* Allow --key-file option in legacy offline encryption.
|
||||
The option was ignored for LUKS1 encryption initialization.
|
||||
|
||||
* Export memory safe functions.
|
||||
To make developing of some extensions simpler, we now export
|
||||
functions to handle memory with proper wipe on deallocation.
|
||||
|
||||
* Fail crypt_keyslot_get_pbkdf for inactive LUKS1 keyslot.
|
||||
|
||||
Libcryptsetup API extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The libcryptsetup API is backward compatible for existing symbols.
|
||||
|
||||
New symbols
|
||||
crypt_set_compatibility
|
||||
crypt_get_compatibility;
|
||||
crypt_resume_by_volume_key;
|
||||
crypt_activate_by_signed_key;
|
||||
crypt_safe_alloc;
|
||||
crypt_safe_realloc;
|
||||
crypt_safe_free;
|
||||
crypt_safe_memzero;
|
||||
|
||||
New defines introduced :
|
||||
CRYPT_BITLK "BITLK" - BITLK (BitLocker-compatible mode
|
||||
CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING - dm-integrity legacy padding
|
||||
CRYPT_VERITY_ROOT_HASH_SIGNATURE - dm-verity root hash signature
|
||||
CRYPT_ACTIVATE_SUSPENDED - device suspended info flag
|
||||
45
docs/v2.3.1-ReleaseNotes
Normal file
45
docs/v2.3.1-ReleaseNotes
Normal file
@@ -0,0 +1,45 @@
|
||||
Cryptsetup 2.3.1 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
|
||||
All users of cryptsetup 2.x should upgrade to this version.
|
||||
|
||||
Changes since version 2.3.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Support VeraCrypt 128 bytes passwords.
|
||||
VeraCrypt now allows passwords of maximal length 128 bytes
|
||||
(compared to legacy TrueCrypt where it was limited by 64 bytes).
|
||||
|
||||
* Strip extra newline from BitLocker recovery keys
|
||||
There might be a trailing newline added by the text editor when
|
||||
the recovery passphrase was passed using the --key-file option.
|
||||
|
||||
* Detect separate libiconv library.
|
||||
It should fix compilation issues on distributions with iconv
|
||||
implemented in a separate library.
|
||||
|
||||
* Various fixes and workarounds to build on old Linux distributions.
|
||||
|
||||
* Split lines with hexadecimal digest printing for large key-sizes.
|
||||
|
||||
* Do not wipe the device with no integrity profile.
|
||||
With --integrity none we performed useless full device wipe.
|
||||
|
||||
* Workaround for dm-integrity kernel table bug.
|
||||
Some kernels show an invalid dm-integrity mapping table
|
||||
if superblock contains the "recalculate" bit. This causes
|
||||
integritysetup to not recognize the dm-integrity device.
|
||||
Integritysetup now specifies kernel options such a way that
|
||||
even on unpatched kernels mapping table is correct.
|
||||
|
||||
* Print error message if LUKS1 keyslot cannot be processed.
|
||||
If the crypto backend is missing support for hash algorithms
|
||||
used in PBKDF2, the error message was not visible.
|
||||
|
||||
* Properly align LUKS2 keyslots area on conversion.
|
||||
If the LUKS1 payload offset (data offset) is not aligned
|
||||
to 4 KiB boundary, new LUKS2 keyslots area in now aligned properly.
|
||||
|
||||
* Validate LUKS2 earlier on conversion to not corrupt the device
|
||||
if binary keyslots areas metadata are not correct.
|
||||
42
docs/v2.3.2-ReleaseNotes
Normal file
42
docs/v2.3.2-ReleaseNotes
Normal file
@@ -0,0 +1,42 @@
|
||||
Cryptsetup 2.3.2 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
|
||||
All users of cryptsetup 2.x should upgrade to this version.
|
||||
|
||||
Changes since version 2.3.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Support compilation with json-c library version 0.14.
|
||||
|
||||
* Update FAQ document for some LUKS2 specific information.
|
||||
|
||||
* Add option to dump content of LUKS2 unbound keyslot:
|
||||
cryptsetup luksDump --unbound -S <slot> <device>
|
||||
or optionally with --master-key-file option.
|
||||
|
||||
The slot number --key-slot (-S) option is mandatory here.
|
||||
|
||||
An unbound keyslot store a key is that is not assigned to data
|
||||
area on disk (LUKS2 allows to store arbitrary keys).
|
||||
|
||||
* Rephrase some error messages and remove redundant end-of-lines.
|
||||
|
||||
* Add support for discards (TRIM) for standalone dm-integrity devices.
|
||||
Linux kernel 5.7 adds support for optional discard/TRIM operation
|
||||
over dm-integrity devices.
|
||||
|
||||
It is now supported through --allow-discards integritysetup option.
|
||||
Note you need to add this flag in all activation calls.
|
||||
|
||||
Note that this option cannot be used for LUKS2 authenticated encryption
|
||||
(that uses dm-integrity for storing additional per-sector metadata).
|
||||
|
||||
* Fix cryptsetup-reencrypt to work on devices that do not allow
|
||||
direct-io device access.
|
||||
|
||||
* Fix a crash in the BitLocker-compatible code error path.
|
||||
|
||||
* Fix Veracrypt compatible support for longer (>64 bytes) passphrases.
|
||||
It allows some older images to be correctly opened again.
|
||||
The issue was introduced in version 2.3.1.
|
||||
@@ -3,10 +3,18 @@ pkgconfig_DATA = lib/libcryptsetup.pc
|
||||
|
||||
lib_LTLIBRARIES = libcryptsetup.la
|
||||
|
||||
noinst_LTLIBRARIES += libutils_io.la
|
||||
|
||||
include_HEADERS = lib/libcryptsetup.h
|
||||
|
||||
EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym
|
||||
|
||||
libutils_io_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
libutils_io_la_SOURCES = \
|
||||
lib/utils_io.c \
|
||||
lib/utils_io.h
|
||||
|
||||
libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/crypto_backend \
|
||||
-I $(top_srcdir)/lib/luks1 \
|
||||
@@ -14,9 +22,10 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/loopaes \
|
||||
-I $(top_srcdir)/lib/verity \
|
||||
-I $(top_srcdir)/lib/tcrypt \
|
||||
-I $(top_srcdir)/lib/integrity
|
||||
-I $(top_srcdir)/lib/integrity \
|
||||
-I $(top_srcdir)/lib/bitlk
|
||||
|
||||
libcryptsetup_la_DEPENDENCIES = libcrypto_backend.la lib/libcryptsetup.sym
|
||||
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
|
||||
|
||||
libcryptsetup_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
|
||||
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
|
||||
@@ -30,7 +39,10 @@ libcryptsetup_la_LIBADD = \
|
||||
@CRYPTO_LIBS@ \
|
||||
@LIBARGON2_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
libcrypto_backend.la
|
||||
@BLKID_LIBS@ \
|
||||
$(LTLIBICONV) \
|
||||
libcrypto_backend.la \
|
||||
libutils_io.la
|
||||
|
||||
libcryptsetup_la_SOURCES = \
|
||||
lib/setup.c \
|
||||
@@ -54,6 +66,9 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/utils_device_locking.c \
|
||||
lib/utils_device_locking.h \
|
||||
lib/utils_pbkdf.c \
|
||||
lib/utils_safe_memory.c \
|
||||
lib/utils_storage_wrappers.c \
|
||||
lib/utils_storage_wrappers.h \
|
||||
lib/libdevmapper.c \
|
||||
lib/utils_dm.h \
|
||||
lib/volumekey.c \
|
||||
@@ -62,7 +77,7 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/base64.h \
|
||||
lib/base64.c \
|
||||
lib/integrity/integrity.h \
|
||||
lib/integrity/integrity.c \
|
||||
lib/integrity/integrity.c \
|
||||
lib/loopaes/loopaes.h \
|
||||
lib/loopaes/loopaes.c \
|
||||
lib/tcrypt/tcrypt.h \
|
||||
@@ -77,7 +92,8 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/verity/verity.c \
|
||||
lib/verity/verity.h \
|
||||
lib/verity/rs_encode_char.c \
|
||||
lib/verity/rs.h \
|
||||
lib/verity/rs_decode_char.c \
|
||||
lib/verity/rs.h \
|
||||
lib/luks2/luks2_disk_metadata.c \
|
||||
lib/luks2/luks2_json_format.c \
|
||||
lib/luks2/luks2_json_metadata.c \
|
||||
@@ -86,7 +102,14 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_digest_pbkdf2.c \
|
||||
lib/luks2/luks2_keyslot.c \
|
||||
lib/luks2/luks2_keyslot_luks2.c \
|
||||
lib/luks2/luks2_keyslot_reenc.c \
|
||||
lib/luks2/luks2_reencrypt.c \
|
||||
lib/luks2/luks2_segment.c \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
lib/luks2/luks2_internal.h \
|
||||
lib/luks2/luks2.h
|
||||
lib/luks2/luks2.h \
|
||||
lib/utils_blkid.c \
|
||||
lib/utils_blkid.h \
|
||||
lib/bitlk/bitlk.h \
|
||||
lib/bitlk/bitlk.c
|
||||
|
||||
10
lib/base64.c
10
lib/base64.c
@@ -1,5 +1,5 @@
|
||||
/* base64.c -- Encode binary data using printable characters.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2019 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -12,13 +12,13 @@
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
|
||||
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
|
||||
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
|
||||
*
|
||||
* See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
|
||||
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
|
||||
*
|
||||
* Be careful with error checking. Here is how you would typically
|
||||
* use these functions:
|
||||
@@ -70,7 +70,7 @@ base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
|
||||
{
|
||||
while (inlen)
|
||||
{
|
||||
*out++ = b64c[to_uchar (in[0]) >> 2];
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
|
||||
*out++ = b64c[to_uchar (in[2]) & 0x3f];
|
||||
@@ -103,7 +103,7 @@ base64_encode (const char *restrict in, size_t inlen,
|
||||
|
||||
while (inlen && outlen)
|
||||
{
|
||||
*out++ = b64c[to_uchar (in[0]) >> 2];
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* base64.h -- Encode binary data using printable characters.
|
||||
Copyright (C) 2004-2006, 2009-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004-2006, 2009-2019 Free Software Foundation, Inc.
|
||||
Written by Simon Josefsson.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -13,7 +13,7 @@
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BASE64_H
|
||||
# define BASE64_H
|
||||
|
||||
1204
lib/bitlk/bitlk.c
Normal file
1204
lib/bitlk/bitlk.c
Normal file
File diff suppressed because it is too large
Load Diff
130
lib/bitlk/bitlk.h
Normal file
130
lib/bitlk/bitlk.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* BITLK (BitLocker-compatible) header definition
|
||||
*
|
||||
* Copyright (C) 2019-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2019-2020 Milan Broz
|
||||
* Copyright (C) 2019-2020 Vojtech Trefny
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTSETUP_BITLK_H
|
||||
#define _CRYPTSETUP_BITLK_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct crypt_device;
|
||||
struct device;
|
||||
|
||||
#define BITLK_NONCE_SIZE 12
|
||||
#define BITLK_SALT_SIZE 16
|
||||
#define BITLK_VMK_MAC_TAG_SIZE 16
|
||||
|
||||
#define BITLK_STATE_NORMAL 0x0004
|
||||
|
||||
typedef enum {
|
||||
BITLK_ENCRYPTION_TYPE_NORMAL = 0,
|
||||
BITLK_ENCRYPTION_TYPE_EOW,
|
||||
BITLK_ENCRYPTION_TYPE_UNKNOWN,
|
||||
} BITLKEncryptionType;
|
||||
|
||||
typedef enum {
|
||||
BITLK_PROTECTION_CLEAR_KEY = 0,
|
||||
BITLK_PROTECTION_TPM,
|
||||
BITLK_PROTECTION_STARTUP_KEY,
|
||||
BITLK_PROTECTION_TPM_PIN,
|
||||
BITLK_PROTECTION_RECOVERY_PASSPHRASE,
|
||||
BITLK_PROTECTION_PASSPHRASE,
|
||||
BITLK_PROTECTION_SMART_CARD,
|
||||
BITLK_PROTECTION_UNKNOWN,
|
||||
} BITLKVMKProtection;
|
||||
|
||||
typedef enum {
|
||||
BITLK_ENTRY_TYPE_PROPERTY = 0x0000,
|
||||
BITLK_ENTRY_TYPE_VMK = 0x0002,
|
||||
BITLK_ENTRY_TYPE_FVEK = 0x0003,
|
||||
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
|
||||
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
|
||||
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
|
||||
} BITLKFVEEntryType;
|
||||
|
||||
typedef enum {
|
||||
BITLK_ENTRY_VALUE_ERASED = 0x0000,
|
||||
BITLK_ENTRY_VALUE_KEY = 0x0001,
|
||||
BITLK_ENTRY_VALUE_STRING = 0x0002,
|
||||
BITLK_ENTRY_VALUE_STRETCH_KEY = 0x0003,
|
||||
BITLK_ENTRY_VALUE_USE_KEY = 0x0004,
|
||||
BITLK_ENTRY_VALUE_ENCRYPTED_KEY = 0x0005,
|
||||
BITLK_ENTRY_VALUE_TPM_KEY = 0x0006,
|
||||
BITLK_ENTRY_VALUE_VALIDATION = 0x0007,
|
||||
BITLK_ENTRY_VALUE_VMK = 0x0008,
|
||||
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
|
||||
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
|
||||
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
|
||||
} BITLKFVEEntryValue;
|
||||
|
||||
struct bitlk_vmk {
|
||||
char *guid;
|
||||
char *name;
|
||||
BITLKVMKProtection protection;
|
||||
uint8_t salt[BITLK_SALT_SIZE];
|
||||
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
|
||||
uint8_t nonce[BITLK_NONCE_SIZE];
|
||||
struct volume_key *vk;
|
||||
struct bitlk_vmk *next;
|
||||
};
|
||||
|
||||
struct bitlk_fvek {
|
||||
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
|
||||
uint8_t nonce[BITLK_NONCE_SIZE];
|
||||
struct volume_key *vk;
|
||||
};
|
||||
|
||||
struct bitlk_metadata {
|
||||
bool togo;
|
||||
bool state;
|
||||
BITLKEncryptionType type;
|
||||
const char *cipher;
|
||||
const char *cipher_mode;
|
||||
uint16_t key_size;
|
||||
char *guid;
|
||||
uint64_t creation_time;
|
||||
char *description;
|
||||
uint64_t metadata_offset[3];
|
||||
uint32_t metadata_version;
|
||||
uint64_t volume_header_offset;
|
||||
uint64_t volume_header_size;
|
||||
struct bitlk_vmk *vmks;
|
||||
struct bitlk_fvek *fvek;
|
||||
};
|
||||
|
||||
int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params);
|
||||
|
||||
int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_metadata *params);
|
||||
|
||||
int BITLK_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *password,
|
||||
size_t passwordLen,
|
||||
const struct bitlk_metadata *params,
|
||||
uint32_t flags);
|
||||
|
||||
void BITLK_bitlk_fvek_free(struct bitlk_fvek *fvek);
|
||||
void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk);
|
||||
void BITLK_bitlk_metadata_free(struct bitlk_metadata *params);
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* cryptsetup plain device helper functions
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -64,7 +64,7 @@ static int hash(const char *hash_name, size_t key_size, char *key,
|
||||
|
||||
#define PLAIN_HASH_LEN_MAX 256
|
||||
|
||||
int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
|
||||
int crypt_plain_hash(struct crypt_device *cd,
|
||||
const char *hash_name,
|
||||
char *key, size_t key_size,
|
||||
const char *passphrase, size_t passphrase_size)
|
||||
@@ -73,7 +73,7 @@ int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
|
||||
size_t hash_size, pad_size;
|
||||
int r;
|
||||
|
||||
log_dbg("Plain: hashing passphrase using %s.", hash_name);
|
||||
log_dbg(cd, "Plain: hashing passphrase using %s.", hash_name);
|
||||
|
||||
if (strlen(hash_name) >= PLAIN_HASH_LEN_MAX)
|
||||
return -EINVAL;
|
||||
@@ -85,11 +85,11 @@ int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
|
||||
*s = '\0';
|
||||
s++;
|
||||
if (!*s || sscanf(s, "%zd", &hash_size) != 1) {
|
||||
log_dbg("Hash length is not a number");
|
||||
log_dbg(cd, "Hash length is not a number");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (hash_size > key_size) {
|
||||
log_dbg("Hash length %zd > key length %zd",
|
||||
log_dbg(cd, "Hash length %zd > key length %zd",
|
||||
hash_size, key_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
|
||||
/* No hash, copy passphrase directly */
|
||||
if (!strcmp(hash_name_buf, "plain")) {
|
||||
if (passphrase_size < hash_size) {
|
||||
log_dbg("Too short plain passphrase.");
|
||||
log_dbg(cd, "Too short plain passphrase.");
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(key, passphrase, hash_size);
|
||||
|
||||
@@ -4,11 +4,14 @@ libcrypto_backend_la_CFLAGS = $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libcrypto_backend_la_SOURCES = \
|
||||
lib/crypto_backend/crypto_backend.h \
|
||||
lib/crypto_backend/crypto_backend_internal.h \
|
||||
lib/crypto_backend/crypto_cipher_kernel.c \
|
||||
lib/crypto_backend/crypto_storage.c \
|
||||
lib/crypto_backend/pbkdf_check.c \
|
||||
lib/crypto_backend/crc32.c \
|
||||
lib/crypto_backend/argon2_generic.c
|
||||
lib/crypto_backend/argon2_generic.c \
|
||||
lib/crypto_backend/cipher_generic.c \
|
||||
lib/crypto_backend/cipher_check.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
noinst_LTLIBRARIES += libargon2.la
|
||||
|
||||
libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) -I lib/crypto_backend/argon2/blake2
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I lib/crypto_backend/argon2 \
|
||||
-I lib/crypto_backend/argon2/blake2
|
||||
|
||||
libargon2_la_SOURCES = \
|
||||
lib/crypto_backend/argon2/blake2/blake2b.c \
|
||||
lib/crypto_backend/argon2/blake2/blake2.h \
|
||||
lib/crypto_backend/argon2/blake2/blake2-impl.h \
|
||||
lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/argon2.c \
|
||||
lib/crypto_backend/argon2/argon2.h \
|
||||
lib/crypto_backend/argon2/core.c \
|
||||
lib/crypto_backend/argon2/core.h \
|
||||
lib/crypto_backend/argon2/encoding.c \
|
||||
lib/crypto_backend/argon2/encoding.h \
|
||||
lib/crypto_backend/argon2/ref.c \
|
||||
lib/crypto_backend/argon2/thread.c \
|
||||
lib/crypto_backend/argon2/thread.h
|
||||
|
||||
if CRYPTO_INTERNAL_SSE_ARGON2
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-opt.h \
|
||||
lib/crypto_backend/argon2/opt.c
|
||||
else
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/ref.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/LICENSE
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/README
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "encoding.h"
|
||||
#include "core.h"
|
||||
|
||||
/* to silent gcc -Wcast-qual for const cast */
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
const char *argon2_type2string(argon2_type type, int uppercase) {
|
||||
switch (type) {
|
||||
case Argon2_d:
|
||||
@@ -271,6 +274,7 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
||||
}
|
||||
|
||||
/* No field can be longer than the encoded length */
|
||||
/* coverity[strlen_assign] */
|
||||
max_field_len = (uint32_t)encoded_len;
|
||||
|
||||
ctx.saltlen = max_field_len;
|
||||
@@ -283,7 +287,7 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx.pwd = (uint8_t *)pwd;
|
||||
ctx.pwd = CONST_CAST(uint8_t *)pwd;
|
||||
ctx.pwdlen = (uint32_t)pwdlen;
|
||||
|
||||
ret = decode_string(&ctx, encoded, type);
|
||||
@@ -346,7 +350,7 @@ int argon2_verify_ctx(argon2_context *context, const char *hash,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) {
|
||||
if (argon2_compare(CONST_CAST(uint8_t *)hash, context->out, context->outlen)) {
|
||||
return ARGON2_VERIFY_MISMATCH;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,13 @@ extern "C" {
|
||||
/* Symbols visibility control */
|
||||
#ifdef A2_VISCTL
|
||||
#define ARGON2_PUBLIC __attribute__((visibility("default")))
|
||||
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#elif _MSC_VER
|
||||
#define ARGON2_PUBLIC __declspec(dllexport)
|
||||
#define ARGON2_LOCAL
|
||||
#else
|
||||
#define ARGON2_PUBLIC
|
||||
#define ARGON2_LOCAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -90,7 +93,7 @@ extern "C" {
|
||||
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
|
||||
|
||||
/* Global flag to determine if we are wiping internal memory buffers. This flag
|
||||
* is defined in core.c and deafults to 1 (wipe internal memory). */
|
||||
* is defined in core.c and defaults to 1 (wipe internal memory). */
|
||||
extern int FLAG_clear_internal_memory;
|
||||
|
||||
/* Error codes */
|
||||
|
||||
@@ -151,6 +151,4 @@ static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (64 - c));
|
||||
}
|
||||
|
||||
void clear_internal_memory(void *v, size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#ifndef PORTABLE_BLAKE2_H
|
||||
#define PORTABLE_BLAKE2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../argon2.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
@@ -69,19 +67,19 @@ enum {
|
||||
};
|
||||
|
||||
/* Streaming API */
|
||||
int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
size_t keylen);
|
||||
int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
|
||||
/* Argon2 Team - Begin Code */
|
||||
int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
/* Argon2 Team - End Code */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "blake2.h"
|
||||
#include "blake2-impl.h"
|
||||
|
||||
void clear_internal_memory(void *v, size_t n);
|
||||
|
||||
static const uint64_t blake2b_IV[8] = {
|
||||
UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),
|
||||
UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),
|
||||
|
||||
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef BLAKE_ROUND_MKA_OPT_H
|
||||
#define BLAKE_ROUND_MKA_OPT_H
|
||||
|
||||
#include "blake2-impl.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
#if defined(__SSSE3__)
|
||||
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */
|
||||
#endif
|
||||
|
||||
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__AVX512F__)
|
||||
#if !defined(__AVX2__)
|
||||
#if !defined(__XOP__)
|
||||
#if defined(__SSSE3__)
|
||||
#define r16 \
|
||||
(_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define r24 \
|
||||
(_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define _mm_roti_epi64(x, c) \
|
||||
(-(c) == 32) \
|
||||
? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \
|
||||
: (-(c) == 24) \
|
||||
? _mm_shuffle_epi8((x), r24) \
|
||||
: (-(c) == 16) \
|
||||
? _mm_shuffle_epi8((x), r16) \
|
||||
: (-(c) == 63) \
|
||||
? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_add_epi64((x), (x))) \
|
||||
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_slli_epi64((x), 64 - (-(c))))
|
||||
#else /* defined(__SSE2__) */
|
||||
#define _mm_roti_epi64(r, c) \
|
||||
_mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {
|
||||
const __m128i z = _mm_mul_epu32(x, y);
|
||||
return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -32); \
|
||||
D1 = _mm_roti_epi64(D1, -32); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -24); \
|
||||
B1 = _mm_roti_epi64(B1, -24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -16); \
|
||||
D1 = _mm_roti_epi64(D1, -16); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -63); \
|
||||
B1 = _mm_roti_epi64(B1, -63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
t1 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
t1 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
#else /* SSE2 */
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = D0; \
|
||||
__m128i t1 = B0; \
|
||||
D0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = D0; \
|
||||
D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \
|
||||
D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0, t1; \
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
t0 = B0; \
|
||||
t1 = D0; \
|
||||
B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \
|
||||
B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
#endif
|
||||
|
||||
#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
#else /* __AVX2__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))
|
||||
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))
|
||||
|
||||
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr32(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
\
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr24(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr32(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
\
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr24(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr16(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr63(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr16(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr63(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while(0);
|
||||
|
||||
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#endif /* __AVX2__ */
|
||||
|
||||
#else /* __AVX512F__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define ror64(x, n) _mm512_ror_epi64((x), (n))
|
||||
|
||||
static __m512i muladd(__m512i x, __m512i y)
|
||||
{
|
||||
__m512i z = _mm512_mul_epu32(x, y);
|
||||
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 32); \
|
||||
D1 = ror64(D1, 32); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 24); \
|
||||
B1 = ror64(B1, 24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 16); \
|
||||
D1 = ror64(D1, 16); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 63); \
|
||||
B1 = ror64(B1, 63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define SWAP_HALVES(A0, A1) \
|
||||
do { \
|
||||
__m512i t0, t1; \
|
||||
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
|
||||
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
|
||||
A0 = t0; \
|
||||
A1 = t1; \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define SWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define UNSWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
SWAP_QUARTERS(A0, A1); \
|
||||
SWAP_QUARTERS(B0, B1); \
|
||||
SWAP_QUARTERS(C0, C1); \
|
||||
SWAP_QUARTERS(D0, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
UNSWAP_QUARTERS(A0, A1); \
|
||||
UNSWAP_QUARTERS(B0, B1); \
|
||||
UNSWAP_QUARTERS(C0, C1); \
|
||||
UNSWAP_QUARTERS(D0, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#endif /* __AVX512F__ */
|
||||
#endif /* BLAKE_ROUND_MKA_OPT_H */
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "blake2.h"
|
||||
#include "blake2-impl.h"
|
||||
|
||||
/*designed by the Lyra PHC team */
|
||||
/* designed by the Lyra PHC team */
|
||||
static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
|
||||
const uint64_t m = UINT64_C(0xFFFFFFFF);
|
||||
const uint64_t xy = (x & m) * (y & m);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#endif
|
||||
#define VC_GE_2005(version) (version >= 1400)
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -126,7 +125,7 @@ void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
|
||||
SecureZeroMemory(v, n);
|
||||
#elif defined memset_s
|
||||
memset_s(v, n, 0, n);
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero(v, n);
|
||||
#else
|
||||
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
|
||||
@@ -300,7 +299,7 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
|
||||
|
||||
for (r = 0; r < instance->passes; ++r) {
|
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
|
||||
uint32_t l;
|
||||
uint32_t l, ll;
|
||||
|
||||
/* 2. Calling threads */
|
||||
for (l = 0; l < instance->lanes; ++l) {
|
||||
@@ -325,6 +324,9 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
|
||||
sizeof(argon2_position_t));
|
||||
if (argon2_thread_create(&thread[l], &fill_segment_thr,
|
||||
(void *)&thr_data[l])) {
|
||||
/* Wait for already running threads */
|
||||
for (ll = 0; ll < l; ++ll)
|
||||
argon2_thread_join(thread[ll]);
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -396,11 +398,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_PWD_PTR_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
#if ARGON2_MIN_PWD_LENGTH > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {
|
||||
return ARGON2_PWD_TOO_SHORT;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
|
||||
return ARGON2_PWD_TOO_LONG;
|
||||
}
|
||||
@@ -426,9 +428,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_SECRET_PTR_MISMATCH;
|
||||
}
|
||||
} else {
|
||||
#if ARGON2_MIN_SECRET > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_SECRET > context->secretlen) {
|
||||
return ARGON2_SECRET_TOO_SHORT;
|
||||
}
|
||||
#endif
|
||||
if (ARGON2_MAX_SECRET < context->secretlen) {
|
||||
return ARGON2_SECRET_TOO_LONG;
|
||||
}
|
||||
@@ -440,9 +444,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_AD_PTR_MISMATCH;
|
||||
}
|
||||
} else {
|
||||
#if ARGON2_MIN_AD_LENGTH > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_AD_LENGTH > context->adlen) {
|
||||
return ARGON2_AD_TOO_SHORT;
|
||||
}
|
||||
#endif
|
||||
if (ARGON2_MAX_AD_LENGTH < context->adlen) {
|
||||
return ARGON2_AD_TOO_LONG;
|
||||
}
|
||||
@@ -452,11 +458,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
if (ARGON2_MIN_MEMORY > context->m_cost) {
|
||||
return ARGON2_MEMORY_TOO_LITTLE;
|
||||
}
|
||||
|
||||
#if 0 /* UINT32_MAX, cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MAX_MEMORY < context->m_cost) {
|
||||
return ARGON2_MEMORY_TOO_MUCH;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (context->m_cost < 8 * context->lanes) {
|
||||
return ARGON2_MEMORY_TOO_LITTLE;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ enum argon2_core_constants {
|
||||
ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
|
||||
ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
|
||||
ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
|
||||
ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
|
||||
|
||||
/* Number of pseudo-random values generated by one call to Blake in Argon2i
|
||||
to
|
||||
|
||||
283
lib/crypto_backend/argon2/opt.c
Normal file
283
lib/crypto_backend/argon2/opt.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "argon2.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "blake2/blake2.h"
|
||||
#include "blake2/blamka-round-opt.h"
|
||||
|
||||
/*
|
||||
* Function fills a new memory block and optionally XORs the old block over the new one.
|
||||
* Memory must be initialized.
|
||||
* @param state Pointer to the just produced block. Content will be updated(!)
|
||||
* @param ref_block Pointer to the reference block
|
||||
* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block
|
||||
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
|
||||
* @pre all block pointers must be valid
|
||||
*/
|
||||
#if defined(__AVX512F__)
|
||||
static void fill_block(__m512i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
block_XY[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_1(
|
||||
state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
|
||||
state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_2(
|
||||
state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
|
||||
state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(state[i], block_XY[i]);
|
||||
_mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
static void fill_block(__m256i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
block_XY[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
|
||||
state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
|
||||
state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(state[i], block_XY[i]);
|
||||
_mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void fill_block(__m128i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
block_XY[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
|
||||
state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
|
||||
state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
|
||||
state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
|
||||
state[8 * 6 + i], state[8 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(state[i], block_XY[i]);
|
||||
_mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void next_addresses(block *address_block, block *input_block) {
|
||||
/*Temporary zero-initialized blocks*/
|
||||
#if defined(__AVX512F__)
|
||||
__m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
__m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
__m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
__m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
|
||||
memset(zero_block, 0, sizeof(zero_block));
|
||||
memset(zero2_block, 0, sizeof(zero2_block));
|
||||
|
||||
/*Increasing index counter*/
|
||||
input_block->v[6]++;
|
||||
|
||||
/*First iteration of G*/
|
||||
fill_block(zero_block, input_block, address_block, 0);
|
||||
|
||||
/*Second iteration of G*/
|
||||
fill_block(zero2_block, address_block, address_block, 0);
|
||||
}
|
||||
|
||||
void fill_segment(const argon2_instance_t *instance,
|
||||
argon2_position_t position) {
|
||||
block *ref_block = NULL, *curr_block = NULL;
|
||||
block address_block, input_block;
|
||||
uint64_t pseudo_rand, ref_index, ref_lane;
|
||||
uint32_t prev_offset, curr_offset;
|
||||
uint32_t starting_index, i;
|
||||
#if defined(__AVX512F__)
|
||||
__m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i state[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i state[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
int data_independent_addressing;
|
||||
|
||||
if (instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_independent_addressing =
|
||||
(instance->type == Argon2_i) ||
|
||||
(instance->type == Argon2_id && (position.pass == 0) &&
|
||||
(position.slice < ARGON2_SYNC_POINTS / 2));
|
||||
|
||||
if (data_independent_addressing) {
|
||||
init_block_value(&input_block, 0);
|
||||
|
||||
input_block.v[0] = position.pass;
|
||||
input_block.v[1] = position.lane;
|
||||
input_block.v[2] = position.slice;
|
||||
input_block.v[3] = instance->memory_blocks;
|
||||
input_block.v[4] = instance->passes;
|
||||
input_block.v[5] = instance->type;
|
||||
}
|
||||
|
||||
starting_index = 0;
|
||||
|
||||
if ((0 == position.pass) && (0 == position.slice)) {
|
||||
starting_index = 2; /* we have already generated the first two blocks */
|
||||
|
||||
/* Don't forget to generate the first block of addresses: */
|
||||
if (data_independent_addressing) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Offset of the current block */
|
||||
curr_offset = position.lane * instance->lane_length +
|
||||
position.slice * instance->segment_length + starting_index;
|
||||
|
||||
if (0 == curr_offset % instance->lane_length) {
|
||||
/* Last block in this lane */
|
||||
prev_offset = curr_offset + instance->lane_length - 1;
|
||||
} else {
|
||||
/* Previous block */
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
|
||||
|
||||
for (i = starting_index; i < instance->segment_length;
|
||||
++i, ++curr_offset, ++prev_offset) {
|
||||
/*1.1 Rotating prev_offset if needed */
|
||||
if (curr_offset % instance->lane_length == 1) {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
/* 1.2 Computing the index of the reference block */
|
||||
/* 1.2.1 Taking pseudo-random value from the previous block */
|
||||
if (data_independent_addressing) {
|
||||
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
|
||||
} else {
|
||||
pseudo_rand = instance->memory[prev_offset].v[0];
|
||||
}
|
||||
|
||||
/* 1.2.2 Computing the lane of the reference block */
|
||||
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
|
||||
|
||||
if ((position.pass == 0) && (position.slice == 0)) {
|
||||
/* Can not reference other lanes yet */
|
||||
ref_lane = position.lane;
|
||||
}
|
||||
|
||||
/* 1.2.3 Computing the number of possible reference block within the
|
||||
* lane.
|
||||
*/
|
||||
position.index = i;
|
||||
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
|
||||
ref_lane == position.lane);
|
||||
|
||||
/* 2 Creating a new block */
|
||||
ref_block =
|
||||
instance->memory + instance->lane_length * ref_lane + ref_index;
|
||||
curr_block = instance->memory + curr_offset;
|
||||
if (ARGON2_VERSION_10 == instance->version) {
|
||||
/* version 1.2.1 and earlier: overwrite, not XOR */
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
if(0 == position.pass) {
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
fill_block(state, ref_block, curr_block, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ typedef pthread_t argon2_thread_handle_t;
|
||||
* @param func A function pointer for the thread's entry point. Must not be
|
||||
* NULL.
|
||||
* @param args Pointer that is passed as an argument to @func. May be NULL.
|
||||
* @return 0 if @handle and @func are valid pointers and a thread is successfuly
|
||||
* @return 0 if @handle and @func are valid pointers and a thread is successfully
|
||||
* created.
|
||||
*/
|
||||
int argon2_thread_create(argon2_thread_handle_t *handle,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Argon2 PBKDF2 library wrapper
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
#if HAVE_ARGON2_H
|
||||
#include <argon2.h>
|
||||
#else
|
||||
@@ -77,117 +77,3 @@ int argon2(const char *type, const char *password, size_t password_length,
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
struct test_vector {
|
||||
argon2_type type;
|
||||
unsigned int memory;
|
||||
unsigned int iterations;
|
||||
unsigned int parallelism;
|
||||
const char *password;
|
||||
unsigned int password_length;
|
||||
const char *salt;
|
||||
unsigned int salt_length;
|
||||
const char *key;
|
||||
unsigned int key_length;
|
||||
const char *ad;
|
||||
unsigned int ad_length;
|
||||
const char *output;
|
||||
unsigned int output_length;
|
||||
};
|
||||
|
||||
struct test_vector test_vectors[] = {
|
||||
/* Argon2 RFC */
|
||||
{
|
||||
Argon2_i, 32, 3, 4,
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02"
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
|
||||
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
|
||||
"\x04\x04\x04\x04\x04\x04\x04\x04"
|
||||
"\x04\x04\x04\x04", 12,
|
||||
"\xc8\x14\xd9\xd1\xdc\x7f\x37\xaa"
|
||||
"\x13\xf0\xd7\x7f\x24\x94\xbd\xa1"
|
||||
"\xc8\xde\x6b\x01\x6d\xd3\x88\xd2"
|
||||
"\x99\x52\xa4\xc4\x67\x2b\x6c\xe8", 32
|
||||
},
|
||||
{
|
||||
Argon2_id, 32, 3, 4,
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02"
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
|
||||
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
|
||||
"\x04\x04\x04\x04\x04\x04\x04\x04"
|
||||
"\x04\x04\x04\x04", 12,
|
||||
"\x0d\x64\x0d\xf5\x8d\x78\x76\x6c"
|
||||
"\x08\xc0\x37\xa3\x4a\x8b\x53\xc9"
|
||||
"\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
|
||||
"\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
|
||||
}
|
||||
};
|
||||
|
||||
static void printhex(const char *s, const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s: ", s);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("\\x%02x", (unsigned char)buf[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int argon2_test_vectors(void)
|
||||
{
|
||||
char result[64];
|
||||
int i, r;
|
||||
struct test_vector *vec;
|
||||
argon2_context context;
|
||||
|
||||
printf("Argon2 running test vectors\n");
|
||||
|
||||
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
|
||||
vec = &test_vectors[i];
|
||||
memset(result, 0, sizeof(result));
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
context.flags = ARGON2_DEFAULT_FLAGS;
|
||||
context.version = ARGON2_VERSION_NUMBER;
|
||||
context.out = (uint8_t *)result;
|
||||
context.outlen = (uint32_t)vec->output_length;
|
||||
context.pwd = (uint8_t *)vec->password;
|
||||
context.pwdlen = (uint32_t)vec->password_length;
|
||||
context.salt = (uint8_t *)vec->salt;
|
||||
context.saltlen = (uint32_t)vec->salt_length;
|
||||
context.secret = (uint8_t *)vec->key;
|
||||
context.secretlen = (uint32_t)vec->key_length;;
|
||||
context.ad = (uint8_t *)vec->ad;
|
||||
context.adlen = (uint32_t)vec->ad_length;
|
||||
context.t_cost = vec->iterations;
|
||||
context.m_cost = vec->memory;
|
||||
context.lanes = vec->parallelism;
|
||||
context.threads = vec->parallelism;
|
||||
|
||||
r = argon2_ctx(&context, vec->type);
|
||||
if (r != ARGON2_OK) {
|
||||
printf("Argon2 failed %i, vector %d\n", r, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (memcmp(result, vec->output, vec->output_length) != 0) {
|
||||
printf("vector %u\n", i);
|
||||
printhex(" got", result, vec->output_length);
|
||||
printhex("want", vec->output, vec->output_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
161
lib/crypto_backend/cipher_check.c
Normal file
161
lib/crypto_backend/cipher_check.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Cipher performance check
|
||||
*
|
||||
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#ifndef CLOCK_MONOTONIC_RAW
|
||||
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is not simulating storage, so using disk block causes extreme overhead.
|
||||
* Let's use some fixed block size where results are more reliable...
|
||||
*/
|
||||
#define CIPHER_BLOCK_BYTES 65536
|
||||
|
||||
/*
|
||||
* If the measured value is lower, encrypted buffer is probably too small
|
||||
* and calculated values are not reliable.
|
||||
*/
|
||||
#define CIPHER_TIME_MIN_MS 0.001
|
||||
|
||||
/*
|
||||
* The whole test depends on Linux kernel usermode crypto API for now.
|
||||
* (The same implementations are used in dm-crypt though.)
|
||||
*/
|
||||
|
||||
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
|
||||
{
|
||||
double start_ms, end_ms;
|
||||
|
||||
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
|
||||
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
|
||||
|
||||
*ms = end_ms - start_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
|
||||
{
|
||||
struct crypt_cipher_kernel cipher;
|
||||
size_t done = 0, block = CIPHER_BLOCK_BYTES;
|
||||
int r;
|
||||
|
||||
if (buffer_size < block)
|
||||
block = buffer_size;
|
||||
|
||||
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (done < buffer_size) {
|
||||
if ((done + block) > buffer_size)
|
||||
block = buffer_size - done;
|
||||
|
||||
if (enc)
|
||||
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
|
||||
block, iv, iv_size);
|
||||
else
|
||||
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
|
||||
block, iv, iv_size);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
done += block;
|
||||
}
|
||||
|
||||
crypt_cipher_destroy_kernel(&cipher);
|
||||
|
||||
return r;
|
||||
}
|
||||
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
int encrypt, double *ms)
|
||||
{
|
||||
struct timespec start, end;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Using getrusage would be better here but the precision
|
||||
* is not adequate, so better stick with CLOCK_MONOTONIC
|
||||
*/
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = time_ms(&start, &end, ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*ms < CIPHER_TIME_MIN_MS)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double speed_mbs(unsigned long bytes, double ms)
|
||||
{
|
||||
double speed = bytes, s = ms / 1000.;
|
||||
|
||||
return speed / (1024 * 1024) / s;
|
||||
}
|
||||
|
||||
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
double *encryption_mbs, double *decryption_mbs)
|
||||
{
|
||||
double ms_enc, ms_dec, ms;
|
||||
int r, repeat_enc, repeat_dec;
|
||||
|
||||
ms_enc = 0.0;
|
||||
repeat_enc = 1;
|
||||
while (ms_enc < 1000.0) {
|
||||
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
ms_enc += ms;
|
||||
repeat_enc++;
|
||||
}
|
||||
|
||||
ms_dec = 0.0;
|
||||
repeat_dec = 1;
|
||||
while (ms_dec < 1000.0) {
|
||||
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
ms_dec += ms;
|
||||
repeat_dec++;
|
||||
}
|
||||
|
||||
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
|
||||
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
90
lib/crypto_backend/cipher_generic.c
Normal file
90
lib/crypto_backend/cipher_generic.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Linux kernel cipher generic utilities
|
||||
*
|
||||
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
const char *mode;
|
||||
int blocksize;
|
||||
bool wrapped_key;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static const struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", NULL, 16, false },
|
||||
{ "aes", NULL, 16, false },
|
||||
{ "serpent", NULL, 16, false },
|
||||
{ "twofish", NULL, 16, false },
|
||||
{ "anubis", NULL, 16, false },
|
||||
{ "blowfish", NULL, 8, false },
|
||||
{ "camellia", NULL, 16, false },
|
||||
{ "cast5", NULL, 8, false },
|
||||
{ "cast6", NULL, 16, false },
|
||||
{ "des", NULL, 8, false },
|
||||
{ "des3_ede", NULL, 8, false },
|
||||
{ "khazad", NULL, 8, false },
|
||||
{ "seed", NULL, 16, false },
|
||||
{ "tea", NULL, 8, false },
|
||||
{ "xtea", NULL, 8, false },
|
||||
{ "paes", NULL, 16, true }, /* protected AES, s390 wrapped key scheme */
|
||||
{ "xchacha12,aes", "adiantum", 32, false },
|
||||
{ "xchacha20,aes", "adiantum", 32, false },
|
||||
{ "sm4", NULL, 16, false },
|
||||
{ NULL, NULL, 0, false }
|
||||
};
|
||||
|
||||
static const struct cipher_alg *_get_alg(const char *name, const char *mode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
if (!mode || !cipher_algs[i].mode ||
|
||||
!strncasecmp(mode, cipher_algs[i].mode, strlen(cipher_algs[i].mode)))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_ivsize(const char *name, const char *mode)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name, mode);
|
||||
|
||||
if (!ca)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode && !strcasecmp(mode, "ecb"))
|
||||
return 0;
|
||||
|
||||
return ca->blocksize;
|
||||
}
|
||||
|
||||
int crypt_cipher_wrapped_key(const char *name, const char *mode)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name, mode);
|
||||
|
||||
return ca ? (int)ca->wrapped_key : 0;
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
* order from highest-order term to lowest-order term. UARTs transmit
|
||||
* characters in order from LSB to MSB. By storing the CRC this way,
|
||||
* we hand it to the UART in the order low-byte to high-byte; the UART
|
||||
* sends each low-bit to hight-bit; and the result is transmission bit
|
||||
* sends each low-bit to high-bit; and the result is transmission bit
|
||||
* by bit from highest- to lowest-order term without requiring any bit
|
||||
* shuffling on our part. Reception works similarly.
|
||||
*
|
||||
@@ -42,7 +42,6 @@
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
|
||||
static const uint32_t crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
@@ -113,4 +112,3 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,15 +22,16 @@
|
||||
#define _CRYPTO_BACKEND_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
struct crypt_device;
|
||||
struct crypt_hash;
|
||||
struct crypt_hmac;
|
||||
struct crypt_cipher;
|
||||
struct crypt_storage;
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx);
|
||||
int crypt_backend_init(void);
|
||||
void crypt_backend_destroy(void);
|
||||
|
||||
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
|
||||
@@ -43,21 +44,29 @@ int crypt_hash_size(const char *name);
|
||||
int crypt_hash_init(struct crypt_hash **ctx, const char *name);
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length);
|
||||
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length);
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
|
||||
/* HMAC */
|
||||
int crypt_hmac_size(const char *name);
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length);
|
||||
const void *key, size_t key_length);
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length);
|
||||
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length);
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
|
||||
/* RNG (if fips paramater set, must provide FIPS compliance) */
|
||||
/* RNG (if fips parameter set, must provide FIPS compliance) */
|
||||
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
|
||||
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
|
||||
|
||||
|
||||
/* PBKDF*/
|
||||
struct crypt_pbkdf_limits {
|
||||
uint32_t min_iterations, max_iterations;
|
||||
uint32_t min_memory, max_memory;
|
||||
uint32_t min_parallel, max_parallel;
|
||||
};
|
||||
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
@@ -71,52 +80,59 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
uint32_t *iterations_out, uint32_t *memory_out,
|
||||
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr);
|
||||
|
||||
#if USE_INTERNAL_PBKDF2
|
||||
/* internal PBKDF2 implementation */
|
||||
int pkcs5_pbkdf2(const char *hash,
|
||||
const char *P, size_t Plen,
|
||||
const char *S, size_t Slen,
|
||||
unsigned int c,
|
||||
unsigned int dkLen, char *DK,
|
||||
unsigned int hash_block_size);
|
||||
#endif
|
||||
|
||||
/* Argon2 implementation wrapper */
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel);
|
||||
|
||||
/* CRC32 */
|
||||
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
|
||||
|
||||
/* ciphers */
|
||||
int crypt_cipher_blocksize(const char *name);
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_ivsize(const char *name, const char *mode);
|
||||
int crypt_cipher_wrapped_key(const char *name, const char *mode);
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length);
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx);
|
||||
const char *mode, const void *key, size_t key_length);
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx);
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx);
|
||||
|
||||
/* storage encryption wrappers */
|
||||
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
|
||||
/* Benchmark of kernel cipher performance */
|
||||
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
double *encryption_mbs, double *decryption_mbs);
|
||||
|
||||
/* Check availability of a cipher (in kernel only) */
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length);
|
||||
|
||||
/* Storage encryption wrappers */
|
||||
int crypt_storage_init(struct crypt_storage **ctx, size_t sector_size,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
char *key, size_t key_length);
|
||||
int crypt_storage_destroy(struct crypt_storage *ctx);
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
size_t count, char *buffer);
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
size_t count, char *buffer);
|
||||
const void *key, size_t key_length);
|
||||
void crypt_storage_destroy(struct crypt_storage *ctx);
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t iv_offset,
|
||||
uint64_t length, char *buffer);
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t iv_offset,
|
||||
uint64_t length, char *buffer);
|
||||
|
||||
bool crypt_storage_kernel_only(struct crypt_storage *ctx);
|
||||
|
||||
/* Temporary Bitlk helper */
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length);
|
||||
|
||||
/* Memzero helper (memset on stack can be optimized out) */
|
||||
static inline void crypt_backend_memzero(void *s, size_t n)
|
||||
{
|
||||
#ifdef HAVE_EXPLICIT_BZERO
|
||||
explicit_bzero(s, n);
|
||||
#else
|
||||
volatile uint8_t *p = (volatile uint8_t *)s;
|
||||
while(n--) *p++ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _CRYPTO_BACKEND_H */
|
||||
|
||||
63
lib/crypto_backend/crypto_backend_internal.h
Normal file
63
lib/crypto_backend/crypto_backend_internal.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef _CRYPTO_BACKEND_INTERNAL_H
|
||||
#define _CRYPTO_BACKEND_INTERNAL_H
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#if USE_INTERNAL_PBKDF2
|
||||
/* internal PBKDF2 implementation */
|
||||
int pkcs5_pbkdf2(const char *hash,
|
||||
const char *P, size_t Plen,
|
||||
const char *S, size_t Slen,
|
||||
unsigned int c,
|
||||
unsigned int dkLen, char *DK,
|
||||
unsigned int hash_block_size);
|
||||
#endif
|
||||
|
||||
/* Argon2 implementation wrapper */
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel);
|
||||
|
||||
/* Block ciphers: fallback to kernel crypto API */
|
||||
|
||||
struct crypt_cipher_kernel {
|
||||
int tfmfd;
|
||||
int opfd;
|
||||
};
|
||||
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length);
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx);
|
||||
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length);
|
||||
|
||||
#endif /* _CRYPTO_BACKEND_INTERNAL_H */
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation (skcipher)
|
||||
*
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,11 +22,12 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#ifdef ENABLE_AF_ALG
|
||||
|
||||
@@ -39,113 +40,77 @@
|
||||
#define SOL_ALG 279
|
||||
#endif
|
||||
|
||||
struct crypt_cipher {
|
||||
int tfmfd;
|
||||
int opfd;
|
||||
};
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
int blocksize;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", 16 },
|
||||
{ "aes", 16 },
|
||||
{ "serpent", 16 },
|
||||
{ "twofish", 16 },
|
||||
{ "anubis", 16 },
|
||||
{ "blowfish", 8 },
|
||||
{ "camellia", 16 },
|
||||
{ "cast5", 8 },
|
||||
{ "cast6", 16 },
|
||||
{ "des", 8 },
|
||||
{ "des3_ede", 8 },
|
||||
{ "khazad", 8 },
|
||||
{ "seed", 16 },
|
||||
{ "tea", 8 },
|
||||
{ "xtea", 8 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct cipher_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
#ifndef ALG_SET_AEAD_AUTHSIZE
|
||||
#define ALG_SET_AEAD_AUTHSIZE 5
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ciphers
|
||||
*
|
||||
* ENOENT - algorithm not available
|
||||
* ENOTSUP - AF_ALG family not available
|
||||
* (but cannot check specificaly for skcipher API)
|
||||
* (but cannot check specifically for skcipher API)
|
||||
*/
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
|
||||
const void *key, size_t key_length,
|
||||
size_t tag_length, struct sockaddr_alg *sa)
|
||||
{
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->opfd = -1;
|
||||
ctx->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (ctx->tfmfd < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bind(ctx->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->opfd = accept(ctx->tfmfd, NULL, 0);
|
||||
if (ctx->opfd < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
struct sockaddr_alg sa = {
|
||||
.salg_family = AF_ALG,
|
||||
.salg_type = "skcipher",
|
||||
};
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
|
||||
"%s(%s)", mode, name);
|
||||
|
||||
h->opfd = -1;
|
||||
h->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (h->tfmfd < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bind(h->tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "cipher_null"))
|
||||
length = 0;
|
||||
key_length = 0;
|
||||
|
||||
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, buffer, length) < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
|
||||
|
||||
h->opfd = accept(h->tfmfd, NULL, 0);
|
||||
if (h->opfd < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
|
||||
}
|
||||
|
||||
/* The in/out should be aligned to page boundary */
|
||||
static int crypt_cipher_crypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
uint32_t direction)
|
||||
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, size_t in_length,
|
||||
char *out, size_t out_length,
|
||||
const char *iv, size_t iv_length,
|
||||
uint32_t direction)
|
||||
{
|
||||
int r = 0;
|
||||
ssize_t len;
|
||||
@@ -154,7 +119,7 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
|
||||
uint32_t *type;
|
||||
struct iovec iov = {
|
||||
.iov_base = (void*)(uintptr_t)in,
|
||||
.iov_len = length,
|
||||
.iov_len = in_length,
|
||||
};
|
||||
int iv_msg_size = iv ? CMSG_SPACE(sizeof(*alg_iv) + iv_length) : 0;
|
||||
char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size];
|
||||
@@ -165,7 +130,7 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
if (!in || !out || !length)
|
||||
if (!in || !out || !in_length)
|
||||
return -EINVAL;
|
||||
|
||||
if ((!iv && iv_length) || (iv && !iv_length))
|
||||
@@ -196,74 +161,183 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
|
||||
}
|
||||
|
||||
len = sendmsg(ctx->opfd, &msg, 0);
|
||||
if (len != (ssize_t)length) {
|
||||
if (len != (ssize_t)(in_length)) {
|
||||
r = -EIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
len = read(ctx->opfd, out, length);
|
||||
if (len != (ssize_t)length)
|
||||
len = read(ctx->opfd, out, out_length);
|
||||
if (len != (ssize_t)out_length)
|
||||
r = -EIO;
|
||||
bad:
|
||||
crypt_backend_memzero(buffer, sizeof(buffer));
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_ENCRYPT);
|
||||
return _crypt_cipher_crypt(ctx, in, length, out, length,
|
||||
iv, iv_length, ALG_OP_ENCRYPT);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_DECRYPT);
|
||||
return _crypt_cipher_crypt(ctx, in, length, out, length,
|
||||
iv, iv_length, ALG_OP_DECRYPT);
|
||||
}
|
||||
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
if (ctx->opfd >= 0)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
|
||||
ctx->tfmfd = -1;
|
||||
ctx->opfd = -1;
|
||||
}
|
||||
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher_kernel c;
|
||||
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
|
||||
const char *salg_type;
|
||||
bool aead;
|
||||
int r;
|
||||
struct sockaddr_alg sa = {
|
||||
.salg_family = AF_ALG,
|
||||
};
|
||||
|
||||
aead = integrity && strcmp(integrity, "none");
|
||||
|
||||
/* Remove IV if present */
|
||||
if (mode) {
|
||||
strncpy(mode_name, mode, sizeof(mode_name));
|
||||
mode_name[sizeof(mode_name) - 1] = 0;
|
||||
cipher_iv = strchr(mode_name, '-');
|
||||
if (cipher_iv) {
|
||||
*cipher_iv = '\0';
|
||||
real_mode = mode_name;
|
||||
}
|
||||
}
|
||||
|
||||
salg_type = aead ? "aead" : "skcipher";
|
||||
snprintf((char *)sa.salg_type, sizeof(sa.salg_type), "%s", salg_type);
|
||||
memset(tmp_salg_name, 0, sizeof(tmp_salg_name));
|
||||
|
||||
/* FIXME: this is duplicating a part of devmapper backend */
|
||||
if (aead && !strcmp(integrity, "poly1305"))
|
||||
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc7539(%s,%s)", name, integrity);
|
||||
else if (!real_mode)
|
||||
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
|
||||
else if (aead && !strcmp(real_mode, "ccm"))
|
||||
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc4309(%s(%s))", real_mode, name);
|
||||
else
|
||||
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
|
||||
|
||||
if (r <= 0 || r > (int)(sizeof(sa.salg_name) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(sa.salg_name, tmp_salg_name, sizeof(sa.salg_name));
|
||||
|
||||
key = malloc(key_length);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We cannot use RNG yet, any key works here, tweak the first part if it is split key (XTS). */
|
||||
memset(key, 0xab, key_length);
|
||||
*key = 0xef;
|
||||
|
||||
r = _crypt_cipher_init(&c, key, key_length, 0, &sa);
|
||||
crypt_cipher_destroy_kernel(&c);
|
||||
free(key);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
struct crypt_cipher_kernel c;
|
||||
struct sockaddr_alg sa = {
|
||||
.salg_family = AF_ALG,
|
||||
.salg_type = "aead",
|
||||
.salg_name = "ccm(aes)",
|
||||
};
|
||||
int r;
|
||||
char buffer[128], ccm_iv[16];
|
||||
|
||||
if (length + tag_length > sizeof(buffer))
|
||||
return -EINVAL;
|
||||
|
||||
if (iv_length > sizeof(ccm_iv) - 2)
|
||||
return -EINVAL;
|
||||
|
||||
r = _crypt_cipher_init(&c, key, key_length, tag_length, &sa);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memcpy(buffer, in, length);
|
||||
memcpy(buffer + length, tag, tag_length);
|
||||
|
||||
/* CCM IV - RFC3610 */
|
||||
memset(ccm_iv, 0, sizeof(ccm_iv));
|
||||
ccm_iv[0] = 15 - iv_length - 1;
|
||||
memcpy(ccm_iv + 1, iv, iv_length);
|
||||
memset(ccm_iv + 1 + iv_length, 0, ccm_iv[0] + 1);
|
||||
iv_length = sizeof(ccm_iv);
|
||||
|
||||
r = _crypt_cipher_crypt(&c, buffer, length + tag_length, out, length,
|
||||
ccm_iv, iv_length, ALG_OP_DECRYPT);
|
||||
|
||||
crypt_cipher_destroy_kernel(&c);
|
||||
crypt_backend_memzero(buffer, sizeof(buffer));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#else /* ENABLE_AF_ALG */
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
{
|
||||
/* Cannot check, expect success. */
|
||||
return 0;
|
||||
}
|
||||
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* GCRYPT crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <gcrypt.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
static int crypto_backend_secmem = 1;
|
||||
@@ -43,6 +43,14 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
bool use_kernel;
|
||||
union {
|
||||
struct crypt_cipher_kernel kernel;
|
||||
gcry_cipher_hd_t hd;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Test for wrong Whirlpool variant,
|
||||
* Ref: http://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
|
||||
@@ -81,7 +89,7 @@ static void crypt_hash_test_whirlpool_bug(void)
|
||||
crypto_backend_whirlpool_bug = 1;
|
||||
}
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx)
|
||||
int crypt_backend_init(void)
|
||||
{
|
||||
if (crypto_backend_initialised)
|
||||
return 0;
|
||||
@@ -225,12 +233,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -240,7 +247,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
unsigned int flags = GCRY_MD_FLAG_HMAC;
|
||||
@@ -262,7 +269,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gcry_md_setkey(h->hd, buffer, length)) {
|
||||
if (gcry_md_setkey(h->hd, key, key_length)) {
|
||||
gcry_md_close(h->hd);
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
@@ -301,12 +308,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
@@ -368,3 +374,148 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
static int _cipher_init(gcry_cipher_hd_t *hd, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
{
|
||||
int cipher_id, mode_id;
|
||||
|
||||
cipher_id = gcry_cipher_map_name(name);
|
||||
if (cipher_id == GCRY_CIPHER_MODE_NONE)
|
||||
return -ENOENT;
|
||||
|
||||
if (!strcmp(mode, "ecb"))
|
||||
mode_id = GCRY_CIPHER_MODE_ECB;
|
||||
else if (!strcmp(mode, "cbc"))
|
||||
mode_id = GCRY_CIPHER_MODE_CBC;
|
||||
#if HAVE_DECL_GCRY_CIPHER_MODE_XTS
|
||||
else if (!strcmp(mode, "xts"))
|
||||
mode_id = GCRY_CIPHER_MODE_XTS;
|
||||
#endif
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
if (gcry_cipher_open(hd, cipher_id, mode_id, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_setkey(*hd, buffer, length)) {
|
||||
gcry_cipher_close(*hd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!_cipher_init(&h->u.hd, name, mode, key, key_length)) {
|
||||
h->use_kernel = false;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
h->use_kernel = true;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
crypt_cipher_destroy_kernel(&ctx->u.kernel);
|
||||
else
|
||||
gcry_cipher_close(ctx->u.hd);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_encrypt(ctx->u.hd, out, length, in, length))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_decrypt(ctx->u.hd, out, length, in, length))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return ctx->use_kernel;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
#ifdef GCRY_CCM_BLOCK_LEN
|
||||
gcry_cipher_hd_t hd;
|
||||
uint64_t l[3];
|
||||
int r = -EINVAL;
|
||||
|
||||
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CCM, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_setkey(hd, key, key_length))
|
||||
goto out;
|
||||
|
||||
if (gcry_cipher_setiv(hd, iv, iv_length))
|
||||
goto out;
|
||||
|
||||
l[0] = length;
|
||||
l[1] = 0;
|
||||
l[2] = tag_length;
|
||||
if (gcry_cipher_ctl(hd, GCRYCTL_SET_CCM_LENGTHS, l, sizeof(l)))
|
||||
goto out;
|
||||
|
||||
if (gcry_cipher_decrypt(hd, out, length, in, length))
|
||||
goto out;
|
||||
|
||||
if (gcry_cipher_checktag(hd, tag, tag_length))
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
gcry_cipher_close(hd);
|
||||
return r;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/if_alg.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
/* FIXME: remove later */
|
||||
#ifndef AF_ALG
|
||||
@@ -48,12 +48,21 @@ struct hash_alg {
|
||||
};
|
||||
|
||||
static struct hash_alg hash_algs[] = {
|
||||
{ "sha1", "sha1", 20, 64 },
|
||||
{ "sha256", "sha256", 32, 64 },
|
||||
{ "sha512", "sha512", 64, 128 },
|
||||
{ "ripemd160", "rmd160", 20, 64 },
|
||||
{ "whirlpool", "wp512", 64, 64 },
|
||||
{ NULL, NULL, 0, 0 }
|
||||
{ "sha1", "sha1", 20, 64 },
|
||||
{ "sha224", "sha224", 28, 64 },
|
||||
{ "sha256", "sha256", 32, 64 },
|
||||
{ "sha384", "sha384", 48, 128 },
|
||||
{ "sha512", "sha512", 64, 128 },
|
||||
{ "ripemd160", "rmd160", 20, 64 },
|
||||
{ "whirlpool", "wp512", 64, 64 },
|
||||
{ "sha3-224", "sha3-224", 28, 144 },
|
||||
{ "sha3-256", "sha3-256", 32, 136 },
|
||||
{ "sha3-384", "sha3-384", 48, 104 },
|
||||
{ "sha3-512", "sha3-512", 64, 72 },
|
||||
{ "stribog256","streebog256", 32, 64 },
|
||||
{ "stribog512","streebog512", 64, 64 },
|
||||
{ "sm3", "sm3", 32, 64 },
|
||||
{ NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
struct crypt_hash {
|
||||
@@ -68,6 +77,10 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd,
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
@@ -97,7 +110,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx)
|
||||
int crypt_backend_init(void)
|
||||
{
|
||||
struct utsname uts;
|
||||
struct sockaddr_alg sa = {
|
||||
@@ -181,7 +194,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
}
|
||||
h->hash_len = ha->length;
|
||||
|
||||
strncpy((char *)sa.salg_name, ha->kernel_name, sizeof(sa.salg_name));
|
||||
strncpy((char *)sa.salg_name, ha->kernel_name, sizeof(sa.salg_name)-1);
|
||||
|
||||
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, NULL, 0) < 0) {
|
||||
free(h);
|
||||
@@ -217,7 +230,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
@@ -225,7 +238,6 @@ int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -235,7 +247,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
struct hash_alg *ha;
|
||||
@@ -258,7 +270,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
|
||||
"hmac(%s)", ha->kernel_name);
|
||||
|
||||
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, buffer, length) < 0) {
|
||||
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, key, key_length) < 0) {
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -292,7 +304,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
@@ -300,7 +312,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG - N/A */
|
||||
@@ -335,3 +346,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
|
||||
iv, iv_length, tag, tag_length);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Nettle crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -23,11 +23,19 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <nettle/sha.h>
|
||||
#include <nettle/sha3.h>
|
||||
#include <nettle/hmac.h>
|
||||
#include <nettle/pbkdf2.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static char *version = "Nettle";
|
||||
#if HAVE_NETTLE_VERSION_H
|
||||
#include <nettle/version.h>
|
||||
#define VSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
static const char *version = "Nettle "VSTR(NETTLE_VERSION_MAJOR)"."VSTR(NETTLE_VERSION_MINOR);
|
||||
#else
|
||||
static const char *version = "Nettle";
|
||||
#endif
|
||||
|
||||
typedef void (*init_func) (void *);
|
||||
typedef void (*update_func) (void *, size_t, const uint8_t *);
|
||||
@@ -45,6 +53,24 @@ struct hash_alg {
|
||||
set_key_func hmac_set_key;
|
||||
};
|
||||
|
||||
/* Missing HMAC wrappers in Nettle */
|
||||
#define HMAC_FCE(xxx) \
|
||||
struct xhmac_##xxx##_ctx HMAC_CTX(struct xxx##_ctx); \
|
||||
static void xhmac_##xxx##_set_key(struct xhmac_##xxx##_ctx *ctx, \
|
||||
size_t key_length, const uint8_t *key) \
|
||||
{HMAC_SET_KEY(ctx, &nettle_##xxx, key_length, key);} \
|
||||
static void xhmac_##xxx##_update(struct xhmac_##xxx##_ctx *ctx, \
|
||||
size_t length, const uint8_t *data) \
|
||||
{xxx##_update(&ctx->state, length, data);} \
|
||||
static void xhmac_##xxx##_digest(struct xhmac_##xxx##_ctx *ctx, \
|
||||
size_t length, uint8_t *digest) \
|
||||
{HMAC_DIGEST(ctx, &nettle_##xxx, length, digest);}
|
||||
|
||||
HMAC_FCE(sha3_224);
|
||||
HMAC_FCE(sha3_256);
|
||||
HMAC_FCE(sha3_384);
|
||||
HMAC_FCE(sha3_512);
|
||||
|
||||
static struct hash_alg hash_algs[] = {
|
||||
{ "sha1", SHA1_DIGEST_SIZE,
|
||||
(init_func) sha1_init,
|
||||
@@ -94,6 +120,41 @@ static struct hash_alg hash_algs[] = {
|
||||
(digest_func) hmac_ripemd160_digest,
|
||||
(set_key_func) hmac_ripemd160_set_key,
|
||||
},
|
||||
/* Nettle prior to version 3.2 has incompatible SHA3 implementation */
|
||||
#if NETTLE_SHA3_FIPS202
|
||||
{ "sha3-224", SHA3_224_DIGEST_SIZE,
|
||||
(init_func) sha3_224_init,
|
||||
(update_func) sha3_224_update,
|
||||
(digest_func) sha3_224_digest,
|
||||
(update_func) xhmac_sha3_224_update,
|
||||
(digest_func) xhmac_sha3_224_digest,
|
||||
(set_key_func) xhmac_sha3_224_set_key,
|
||||
},
|
||||
{ "sha3-256", SHA3_256_DIGEST_SIZE,
|
||||
(init_func) sha3_256_init,
|
||||
(update_func) sha3_256_update,
|
||||
(digest_func) sha3_256_digest,
|
||||
(update_func) xhmac_sha3_256_update,
|
||||
(digest_func) xhmac_sha3_256_digest,
|
||||
(set_key_func) xhmac_sha3_256_set_key,
|
||||
},
|
||||
{ "sha3-384", SHA3_384_DIGEST_SIZE,
|
||||
(init_func) sha3_384_init,
|
||||
(update_func) sha3_384_update,
|
||||
(digest_func) sha3_384_digest,
|
||||
(update_func) xhmac_sha3_384_update,
|
||||
(digest_func) xhmac_sha3_384_digest,
|
||||
(set_key_func) xhmac_sha3_384_set_key,
|
||||
},
|
||||
{ "sha3-512", SHA3_512_DIGEST_SIZE,
|
||||
(init_func) sha3_512_init,
|
||||
(update_func) sha3_512_update,
|
||||
(digest_func) sha3_512_digest,
|
||||
(update_func) xhmac_sha3_512_update,
|
||||
(digest_func) xhmac_sha3_512_digest,
|
||||
(set_key_func) xhmac_sha3_512_set_key,
|
||||
},
|
||||
#endif
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, }
|
||||
};
|
||||
|
||||
@@ -105,6 +166,11 @@ struct crypt_hash {
|
||||
struct sha256_ctx sha256;
|
||||
struct sha384_ctx sha384;
|
||||
struct sha512_ctx sha512;
|
||||
struct ripemd160_ctx ripemd160;
|
||||
struct sha3_224_ctx sha3_224;
|
||||
struct sha3_256_ctx sha3_256;
|
||||
struct sha3_384_ctx sha3_384;
|
||||
struct sha3_512_ctx sha3_512;
|
||||
} nettle_ctx;
|
||||
};
|
||||
|
||||
@@ -116,11 +182,20 @@ struct crypt_hmac {
|
||||
struct hmac_sha256_ctx sha256;
|
||||
struct hmac_sha384_ctx sha384;
|
||||
struct hmac_sha512_ctx sha512;
|
||||
struct hmac_ripemd160_ctx ripemd160;
|
||||
struct xhmac_sha3_224_ctx sha3_224;
|
||||
struct xhmac_sha3_256_ctx sha3_256;
|
||||
struct xhmac_sha3_384_ctx sha3_384;
|
||||
struct xhmac_sha3_512_ctx sha3_512;
|
||||
} nettle_ctx;
|
||||
size_t key_length;
|
||||
uint8_t *key;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
uint32_t crypt_backend_flags(void)
|
||||
{
|
||||
return 0;
|
||||
@@ -138,7 +213,7 @@ static struct hash_alg *_get_alg(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx)
|
||||
int crypt_backend_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -202,11 +277,10 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -216,7 +290,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
|
||||
@@ -230,12 +304,12 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
if (!h->hash)
|
||||
goto bad;
|
||||
|
||||
h->key = malloc(length);
|
||||
h->key = malloc(key_length);
|
||||
if (!h->key)
|
||||
goto bad;
|
||||
|
||||
memcpy(h->key, buffer, length);
|
||||
h->key_length = length;
|
||||
memcpy(h->key, key, key_length);
|
||||
h->key_length = key_length;
|
||||
|
||||
h->hash->init(&h->nettle_ctx);
|
||||
h->hash->hmac_set_key(&h->nettle_ctx, h->key_length, h->key);
|
||||
@@ -268,13 +342,12 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
memset(ctx->key, 0, ctx->key_length);
|
||||
free(ctx->key);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG - N/A */
|
||||
@@ -301,8 +374,8 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nettle_pbkdf2(&h->nettle_ctx, h->hash->nettle_hmac_update,
|
||||
h->hash->nettle_hmac_digest, h->hash->length, iterations,
|
||||
nettle_pbkdf2(&h->nettle_ctx, h->hash->hmac_update,
|
||||
h->hash->hmac_digest, h->hash->length, iterations,
|
||||
salt_length, (const uint8_t *)salt, key_length,
|
||||
(uint8_t *)key);
|
||||
crypt_hmac_destroy(h);
|
||||
@@ -314,3 +387,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
|
||||
iv, iv_length, tag, tag_length);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* NSS crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <errno.h>
|
||||
#include <nss.h>
|
||||
#include <pk11pub.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
@@ -59,6 +59,10 @@ struct crypt_hmac {
|
||||
const struct hash_alg *hash;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
static struct hash_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -71,7 +75,7 @@ static struct hash_alg *_get_alg(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx)
|
||||
int crypt_backend_init(void)
|
||||
{
|
||||
if (crypto_backend_initialised)
|
||||
return 0;
|
||||
@@ -180,12 +184,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
PK11_DestroyContext(ctx->md, PR_TRUE);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -195,15 +198,15 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
SECItem keyItem;
|
||||
SECItem noParams;
|
||||
|
||||
keyItem.type = siBuffer;
|
||||
keyItem.data = CONST_CAST(unsigned char *)buffer;
|
||||
keyItem.len = (int)length;
|
||||
keyItem.data = CONST_CAST(unsigned char *)key;
|
||||
keyItem.len = (int)key_length;
|
||||
|
||||
noParams.type = siBuffer;
|
||||
noParams.data = 0;
|
||||
@@ -282,7 +285,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
if (ctx->key)
|
||||
PK11_FreeSymKey(ctx->key);
|
||||
@@ -292,7 +295,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
PK11_DestroyContext(ctx->md, PR_TRUE);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
@@ -333,3 +335,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
|
||||
iv, iv_length, tag, tag_length);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* OPENSSL crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -33,7 +33,9 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
|
||||
@@ -49,10 +51,24 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
bool use_kernel;
|
||||
union {
|
||||
struct crypt_cipher_kernel kernel;
|
||||
struct {
|
||||
EVP_CIPHER_CTX *hd_enc;
|
||||
EVP_CIPHER_CTX *hd_dec;
|
||||
size_t iv_length;
|
||||
} lib;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatible wrappers for OpenSSL < 1.1.0
|
||||
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
static void openssl_backend_init(void)
|
||||
{
|
||||
OpenSSL_add_all_algorithms();
|
||||
@@ -105,7 +121,7 @@ static const char *openssl_backend_version(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
int crypt_backend_init(struct crypt_device *ctx)
|
||||
int crypt_backend_init(void)
|
||||
{
|
||||
if (crypto_backend_initialised)
|
||||
return 0;
|
||||
@@ -213,12 +229,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
EVP_MD_CTX_free(ctx->md);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -228,7 +243,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
|
||||
@@ -249,7 +264,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
HMAC_Init_ex(h->md, buffer, length, h->hash_id, NULL);
|
||||
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
|
||||
|
||||
h->hash_len = EVP_MD_size(h->hash_id);
|
||||
*ctx = h;
|
||||
@@ -288,12 +303,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
HMAC_CTX_free(ctx->md);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
@@ -324,7 +338,7 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
return -EINVAL;
|
||||
|
||||
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
|
||||
(unsigned char *)salt, (int)salt_length,
|
||||
(const unsigned char *)salt, (int)salt_length,
|
||||
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
@@ -335,3 +349,198 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(*hd_enc);
|
||||
*hd_enc = NULL;
|
||||
|
||||
EVP_CIPHER_CTX_free(*hd_dec);
|
||||
*hd_dec = NULL;
|
||||
}
|
||||
|
||||
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
|
||||
const char *mode, const void *key, size_t key_length, size_t *iv_length)
|
||||
{
|
||||
char cipher_name[256];
|
||||
const EVP_CIPHER *type;
|
||||
int r, key_bits;
|
||||
|
||||
key_bits = key_length * 8;
|
||||
if (!strcmp(mode, "xts"))
|
||||
key_bits /= 2;
|
||||
|
||||
r = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", name, key_bits, mode);
|
||||
if (r < 0 || r >= (int)sizeof(cipher_name))
|
||||
return -EINVAL;
|
||||
|
||||
type = EVP_get_cipherbyname(cipher_name);
|
||||
if (!type)
|
||||
return -ENOENT;
|
||||
|
||||
if (EVP_CIPHER_key_length(type) != (int)key_length)
|
||||
return -EINVAL;
|
||||
|
||||
*hd_enc = EVP_CIPHER_CTX_new();
|
||||
*hd_dec = EVP_CIPHER_CTX_new();
|
||||
*iv_length = EVP_CIPHER_iv_length(type);
|
||||
|
||||
if (!*hd_enc || !*hd_dec)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
|
||||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
|
||||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
|
||||
key_length, &h->u.lib.iv_length)) {
|
||||
h->use_kernel = false;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
h->use_kernel = true;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
crypt_cipher_destroy_kernel(&ctx->u.kernel);
|
||||
else
|
||||
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int _cipher_encrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
|
||||
int length, const unsigned char *iv, size_t iv_length)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (ctx->u.lib.iv_length != iv_length)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx->u.lib.hd_enc, NULL, NULL, NULL, iv) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptUpdate(ctx->u.lib.hd_enc, out, &len, in, length) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptFinal(ctx->u.lib.hd_enc, out + len, &len) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cipher_decrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
|
||||
int length, const unsigned char *iv, size_t iv_length)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (ctx->u.lib.iv_length != iv_length)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx->u.lib.hd_dec, NULL, NULL, NULL, iv) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptUpdate(ctx->u.lib.hd_dec, out, &len, in, length) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptFinal(ctx->u.lib.hd_dec, out + len, &len) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
return _cipher_encrypt(ctx, (const unsigned char*)in,
|
||||
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
return _cipher_decrypt(ctx, (const unsigned char*)in,
|
||||
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return ctx->use_kernel;
|
||||
}
|
||||
|
||||
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
const char *tag, size_t tag_length)
|
||||
{
|
||||
#ifdef EVP_CTRL_CCM_SET_IVLEN
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int len = 0, r = -EINVAL;
|
||||
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL) != 1)
|
||||
goto out;
|
||||
|
||||
//EVP_CIPHER_CTX_key_length(ctx)
|
||||
//EVP_CIPHER_CTX_iv_length(ctx)
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_length, NULL) != 1)
|
||||
goto out;
|
||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_length, CONST_CAST(void*)tag) != 1)
|
||||
goto out;
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, (const unsigned char*)iv) != 1)
|
||||
goto out;
|
||||
|
||||
if (EVP_DecryptUpdate(ctx, (unsigned char*)out, &len, (const unsigned char*)in, length) == 1)
|
||||
r = 0;
|
||||
out:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return r;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Generic wrapper for storage encryption modes and Initial Vectors
|
||||
* (reimplementation of some functions from Linux dm-crypt kernel)
|
||||
*
|
||||
* Copyright (C) 2014-2017, Milan Broz
|
||||
* Copyright (C) 2014-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#define SECTOR_SHIFT 9
|
||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||
|
||||
/*
|
||||
* Internal IV helper
|
||||
@@ -41,7 +40,8 @@ struct crypt_sector_iv {
|
||||
|
||||
/* Block encryption storage context */
|
||||
struct crypt_storage {
|
||||
uint64_t sector_start;
|
||||
unsigned sector_shift;
|
||||
unsigned iv_shift;
|
||||
struct crypt_cipher *cipher;
|
||||
struct crypt_sector_iv cipher_iv;
|
||||
};
|
||||
@@ -56,20 +56,23 @@ static int int_log2(unsigned int x)
|
||||
|
||||
static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
|
||||
const char *cipher_name, const char *mode_name,
|
||||
const char *iv_name, char *key, size_t key_length)
|
||||
const char *iv_name, const void *key, size_t key_length)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->iv_size = crypt_cipher_blocksize(cipher_name);
|
||||
ctx->iv_size = crypt_cipher_ivsize(cipher_name, mode_name);
|
||||
if (ctx->iv_size < 8)
|
||||
return -ENOENT;
|
||||
|
||||
if (!iv_name ||
|
||||
!strcmp(cipher_name, "cipher_null") ||
|
||||
if (!strcmp(cipher_name, "cipher_null") ||
|
||||
!strcmp(mode_name, "ecb")) {
|
||||
if (iv_name)
|
||||
return -EINVAL;
|
||||
ctx->type = IV_NONE;
|
||||
ctx->iv_size = 0;
|
||||
return 0;
|
||||
} else if (!iv_name) {
|
||||
return -EINVAL;
|
||||
} else if (!strcasecmp(iv_name, "null")) {
|
||||
ctx->type = IV_NULL;
|
||||
} else if (!strcasecmp(iv_name, "plain64")) {
|
||||
@@ -175,7 +178,7 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
{
|
||||
if (ctx->type == IV_ESSIV)
|
||||
crypt_cipher_destroy(ctx->essiv_cipher);
|
||||
@@ -186,22 +189,26 @@ static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
}
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Block encryption storage wrappers */
|
||||
|
||||
int crypt_storage_init(struct crypt_storage **ctx,
|
||||
uint64_t sector_start,
|
||||
size_t sector_size,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
char *key, size_t key_length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_storage *s;
|
||||
char mode_name[64];
|
||||
char *cipher_iv = NULL;
|
||||
int r = -EIO;
|
||||
|
||||
if (sector_size < (1 << SECTOR_SHIFT) ||
|
||||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
|
||||
sector_size & (sector_size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
s = malloc(sizeof(*s));
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
@@ -228,27 +235,33 @@ int crypt_storage_init(struct crypt_storage **ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
s->sector_start = sector_start;
|
||||
s->sector_shift = int_log2(sector_size);
|
||||
s->iv_shift = s->sector_shift - SECTOR_SHIFT;
|
||||
|
||||
*ctx = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx,
|
||||
uint64_t sector, size_t count,
|
||||
char *buffer)
|
||||
uint64_t iv_offset,
|
||||
uint64_t length, char *buffer)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t i;
|
||||
int r = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
|
||||
if (length & ((1 << ctx->sector_shift) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
length >>= ctx->sector_shift;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (uint64_t)(i << ctx->iv_shift));
|
||||
if (r)
|
||||
break;
|
||||
r = crypt_cipher_decrypt(ctx->cipher,
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
SECTOR_SIZE,
|
||||
&buffer[i << ctx->sector_shift],
|
||||
&buffer[i << ctx->sector_shift],
|
||||
1 << ctx->sector_shift,
|
||||
ctx->cipher_iv.iv,
|
||||
ctx->cipher_iv.iv_size);
|
||||
if (r)
|
||||
@@ -259,20 +272,25 @@ int crypt_storage_decrypt(struct crypt_storage *ctx,
|
||||
}
|
||||
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx,
|
||||
uint64_t sector, size_t count,
|
||||
char *buffer)
|
||||
uint64_t iv_offset,
|
||||
uint64_t length, char *buffer)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t i;
|
||||
int r = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
|
||||
if (length & ((1 << ctx->sector_shift) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
length >>= ctx->sector_shift;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (i << ctx->iv_shift));
|
||||
if (r)
|
||||
break;
|
||||
r = crypt_cipher_encrypt(ctx->cipher,
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
SECTOR_SIZE,
|
||||
&buffer[i << ctx->sector_shift],
|
||||
&buffer[i << ctx->sector_shift],
|
||||
1 << ctx->sector_shift,
|
||||
ctx->cipher_iv.iv,
|
||||
ctx->cipher_iv.iv_size);
|
||||
if (r)
|
||||
@@ -282,10 +300,10 @@ int crypt_storage_encrypt(struct crypt_storage *ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
void crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
crypt_sector_iv_destroy(&ctx->cipher_iv);
|
||||
|
||||
@@ -294,6 +312,9 @@ int crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool crypt_storage_kernel_only(struct crypt_storage *ctx)
|
||||
{
|
||||
return crypt_cipher_kernel_only(ctx->cipher);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (C) 2004 Free Software Foundation
|
||||
*
|
||||
* cryptsetup related changes
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <alloca.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int hash_buf(const char *src, size_t src_len,
|
||||
char *dst, size_t dst_len,
|
||||
@@ -230,197 +230,3 @@ out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
struct test_vector {
|
||||
const char *hash;
|
||||
unsigned int hash_block_length;
|
||||
unsigned int iterations;
|
||||
const char *password;
|
||||
unsigned int password_length;
|
||||
const char *salt;
|
||||
unsigned int salt_length;
|
||||
const char *output;
|
||||
unsigned int output_length;
|
||||
};
|
||||
|
||||
struct test_vector test_vectors[] = {
|
||||
/* RFC 3962 */
|
||||
{
|
||||
"sha1", 64, 1,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01"
|
||||
"\x56\x5a\x11\x22\xb2\x56\x35\x15"
|
||||
"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3"
|
||||
"\x33\xec\xc0\xe2\xe1\xf7\x08\x37", 32
|
||||
}, {
|
||||
"sha1", 64, 2,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e"
|
||||
"\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
|
||||
"\xa0\x53\x78\xb9\x32\x44\xec\x8f"
|
||||
"\x48\xa9\x9e\x61\xad\x79\x9d\x86", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e"
|
||||
"\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
|
||||
"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f"
|
||||
"\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", 32
|
||||
}, {
|
||||
"sha1", 64, 5,
|
||||
"password", 8,
|
||||
"\0224VxxV4\022", 8, // "\x1234567878563412
|
||||
"\xd1\xda\xa7\x86\x15\xf2\x87\xe6"
|
||||
"\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
|
||||
"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6"
|
||||
"\xad\xf4\xfa\x57\x4b\x6e\x64\xee", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 64,
|
||||
"pass phrase equals block size", 29,
|
||||
"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b"
|
||||
"\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
|
||||
"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc"
|
||||
"\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5"
|
||||
"\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
|
||||
"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b"
|
||||
"\x36\xbe\x92\x46\x91\x5e\xc8\x2a", 32
|
||||
}, {
|
||||
"sha1", 64, 50,
|
||||
"\360\235\204\236", 4, // g-clef ("\xf09d849e)
|
||||
"EXAMPLE.COMpianist", 18,
|
||||
"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43"
|
||||
"\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
|
||||
"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2"
|
||||
"\x81\xff\x30\x69\xe1\xe9\x4f\x52", 32
|
||||
}, {
|
||||
/* RFC-6070 */
|
||||
"sha1", 64, 1,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
|
||||
"\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", 20
|
||||
}, {
|
||||
"sha1", 64, 2,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
|
||||
"\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", 20
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
|
||||
"\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20
|
||||
}, {
|
||||
"sha1", 64, 16777216,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
|
||||
"\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 20
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"passwordPASSWORDpassword", 24,
|
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
||||
"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
|
||||
"\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
|
||||
"\x4c\xf2\xf0\x70\x38", 25
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"pass\0word", 9,
|
||||
"sa\0lt", 5,
|
||||
"\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
|
||||
"\xd7\xf0\x34\x25\xe0\xc3", 16
|
||||
}, {
|
||||
/* empty password test */
|
||||
"sha1", 64, 2,
|
||||
"", 0,
|
||||
"salt", 4,
|
||||
"\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
|
||||
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", 20
|
||||
}, {
|
||||
/* Password exceeds block size test */
|
||||
"sha256", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x22\x34\x4b\xc4\xb6\xe3\x26\x75"
|
||||
"\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d"
|
||||
"\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa"
|
||||
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58", 32
|
||||
}, {
|
||||
"sha512", 128, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 129,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d"
|
||||
"\x7d\x8e\xdd\x58\x01\xb4\x59\x72"
|
||||
"\x99\x92\x16\x30\x5e\xa4\x36\x8d"
|
||||
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9", 32
|
||||
}, {
|
||||
"whirlpool", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x9c\x1c\x74\xf5\x88\x26\xe7\x6a"
|
||||
"\x53\x58\xf4\x0c\x39\xe7\x80\x89"
|
||||
"\x07\xc0\x31\x19\x9a\x50\xa2\x48"
|
||||
"\xf1\xd9\xfe\x78\x64\xe5\x84\x50", 32
|
||||
}
|
||||
};
|
||||
|
||||
static void printhex(const char *s, const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s: ", s);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("\\x%02x", (unsigned char)buf[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int pkcs5_pbkdf2_test_vectors(void)
|
||||
{
|
||||
char result[64];
|
||||
unsigned int i, j;
|
||||
struct test_vector *vec;
|
||||
|
||||
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
|
||||
vec = &test_vectors[i];
|
||||
for (j = 1; j <= vec->output_length; j++) {
|
||||
if (pkcs5_pbkdf2(vec->hash,
|
||||
vec->password, vec->password_length,
|
||||
vec->salt, vec->salt_length,
|
||||
vec->iterations,
|
||||
j, result, vec->hash_block_length)) {
|
||||
printf("pbkdf2 failed, vector %d\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (memcmp(result, vec->output, j) != 0) {
|
||||
printf("vector %u\n", i);
|
||||
printhex(" got", result, j);
|
||||
printhex("want", vec->output, j);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(result, 0, sizeof(result));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* PBKDF performance check
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2016-2017, Ondrej Mosnacek
|
||||
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2020 Milan Broz
|
||||
* Copyright (C) 2016-2020 Ondrej Mosnacek
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -27,6 +27,10 @@
|
||||
#include <sys/resource.h>
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#ifndef CLOCK_MONOTONIC_RAW
|
||||
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
|
||||
#endif
|
||||
|
||||
#define BENCH_MIN_MS 250
|
||||
#define BENCH_MIN_MS_FAST 10
|
||||
#define BENCH_PERCENT_ATLEAST 95
|
||||
@@ -34,6 +38,33 @@
|
||||
#define BENCH_SAMPLES_FAST 3
|
||||
#define BENCH_SAMPLES_SLOW 1
|
||||
|
||||
/* These PBKDF2 limits must be never violated */
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *limits)
|
||||
{
|
||||
if (!kdf || !limits)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(kdf, "pbkdf2")) {
|
||||
limits->min_iterations = 1000; /* recommendation in NIST SP 800-132 */
|
||||
limits->max_iterations = UINT32_MAX;
|
||||
limits->min_memory = 0; /* N/A */
|
||||
limits->max_memory = 0; /* N/A */
|
||||
limits->min_parallel = 0; /* N/A */
|
||||
limits->max_parallel = 0; /* N/A */
|
||||
return 0;
|
||||
} else if (!strcmp(kdf, "argon2i") || !strcmp(kdf, "argon2id")) {
|
||||
limits->min_iterations = 4;
|
||||
limits->max_iterations = UINT32_MAX;
|
||||
limits->min_memory = 32;
|
||||
limits->max_memory = 4*1024*1024; /* 4GiB */
|
||||
limits->min_parallel = 1;
|
||||
limits->max_parallel = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long time_ms(struct rusage *start, struct rusage *end)
|
||||
{
|
||||
int count_kernel_time = 0;
|
||||
@@ -124,7 +155,7 @@ static int next_argon2_params(uint32_t *t_cost, uint32_t *m_cost,
|
||||
old_t_cost = *t_cost;
|
||||
old_m_cost = *m_cost;
|
||||
|
||||
if (ms > target_ms) {
|
||||
if ((uint32_t)ms > target_ms) {
|
||||
/* decreasing, first try to lower t_cost, then m_cost */
|
||||
num = (uint64_t)*t_cost * (uint64_t)target_ms;
|
||||
denom = (uint64_t)ms;
|
||||
@@ -175,7 +206,7 @@ static int next_argon2_params(uint32_t *t_cost, uint32_t *m_cost,
|
||||
static int crypt_argon2_check(const char *kdf, const char *password,
|
||||
size_t password_length, const char *salt,
|
||||
size_t salt_length, size_t key_length,
|
||||
uint32_t min_t_cost, uint32_t max_m_cost,
|
||||
uint32_t min_t_cost, uint32_t min_m_cost, uint32_t max_m_cost,
|
||||
uint32_t parallel, uint32_t target_ms,
|
||||
uint32_t *out_t_cost, uint32_t *out_m_cost,
|
||||
int (*progress)(uint32_t time_ms, void *usrptr),
|
||||
@@ -183,7 +214,7 @@ static int crypt_argon2_check(const char *kdf, const char *password,
|
||||
{
|
||||
int r = 0;
|
||||
char *key = NULL;
|
||||
uint32_t t_cost, m_cost, min_m_cost = 8 * parallel;
|
||||
uint32_t t_cost, m_cost;
|
||||
long ms;
|
||||
long ms_atleast = (long)target_ms * BENCH_PERCENT_ATLEAST / 100;
|
||||
long ms_atmost = (long)target_ms * BENCH_PERCENT_ATMOST / 100;
|
||||
@@ -191,6 +222,9 @@ static int crypt_argon2_check(const char *kdf, const char *password,
|
||||
if (key_length <= 0 || target_ms <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (min_m_cost < (parallel * 8))
|
||||
min_m_cost = parallel * 8;
|
||||
|
||||
if (max_m_cost < min_m_cost)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -362,8 +396,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
#define ARGON2_MIN_T_COST 4
|
||||
|
||||
int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_size,
|
||||
const char *salt, size_t salt_size,
|
||||
@@ -372,11 +404,17 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
uint32_t *iterations_out, uint32_t *memory_out,
|
||||
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr)
|
||||
{
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
int r = -EINVAL;
|
||||
|
||||
if (!kdf || !iterations_out || !memory_out)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: whole limits propagation should be more clear here */
|
||||
r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*memory_out = 0;
|
||||
*iterations_out = 0;
|
||||
|
||||
@@ -388,7 +426,9 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
else if (!strncmp(kdf, "argon2", 6))
|
||||
r = crypt_argon2_check(kdf, password, password_size,
|
||||
salt, salt_size, volume_key_size,
|
||||
ARGON2_MIN_T_COST, max_memory_kb,
|
||||
pbkdf_limits.min_iterations,
|
||||
pbkdf_limits.min_memory,
|
||||
max_memory_kb,
|
||||
parallel_threads, time_ms, iterations_out,
|
||||
memory_out, progress, usrptr);
|
||||
return r;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity volume handling
|
||||
*
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "integrity.h"
|
||||
@@ -34,15 +33,14 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
{
|
||||
int devfd, r;
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if(devfd < 0) {
|
||||
devfd = device_open(cd, device, O_RDONLY);
|
||||
if(devfd < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
|
||||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
|
||||
sb->version != SB_VERSION) {
|
||||
sb->version < SB_VERSION_1 || sb->version > SB_VERSION_4) {
|
||||
log_std(cd, "No integrity superblock detected on %s.\n",
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
@@ -50,25 +48,31 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
|
||||
sb->journal_sections = le32toh(sb->journal_sections);
|
||||
sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
|
||||
sb->recalc_sector = le64toh(sb->recalc_sector);
|
||||
sb->flags = le32toh(sb->flags);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params)
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd,
|
||||
struct crypt_params_integrity *params,
|
||||
uint32_t *flags)
|
||||
{
|
||||
struct superblock sb;
|
||||
int r;
|
||||
|
||||
r = INTEGRITY_read_superblock(cd, crypt_data_device(cd), 0, &sb);
|
||||
r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
|
||||
params->tag_size = sb.integrity_tag_size;
|
||||
|
||||
if (flags)
|
||||
*flags = sb.flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -82,11 +86,20 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
return r;
|
||||
|
||||
log_std(cd, "Info for integrity device %s.\n", device_path(device));
|
||||
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
|
||||
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
|
||||
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
|
||||
log_std(cd, "journal_sections %u\n", sb.journal_sections);
|
||||
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
|
||||
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
|
||||
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
|
||||
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
|
||||
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
|
||||
log_std(cd, "flags %s%s%s%s\n",
|
||||
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
|
||||
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
|
||||
sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -106,16 +119,16 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int INTEGRITY_key_size(struct crypt_device *cd)
|
||||
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
|
||||
{
|
||||
const char *integrity = crypt_get_integrity(cd);
|
||||
|
||||
if (!integrity)
|
||||
return 0;
|
||||
|
||||
//FIXME: use crypto backend hash size
|
||||
if (!strcmp(integrity, "aead"))
|
||||
return 0;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
return 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
return 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -128,8 +141,30 @@ int INTEGRITY_key_size(struct crypt_device *cd)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return hash or hmac(hash) size, if known */
|
||||
int INTEGRITY_hash_tag_size(const char *integrity)
|
||||
{
|
||||
char hash[MAX_CIPHER_LEN];
|
||||
int r;
|
||||
|
||||
if (!integrity)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
|
||||
return 4;
|
||||
|
||||
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
|
||||
if (r == 1)
|
||||
r = crypt_hash_size(hash);
|
||||
else
|
||||
r = crypt_hash_size(integrity);
|
||||
|
||||
return r < 0 ? 0 : r;
|
||||
}
|
||||
|
||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
const char *integrity,
|
||||
const char *cipher,
|
||||
const char *cipher_mode)
|
||||
{
|
||||
int iv_tag_size = 0, auth_tag_size = 0;
|
||||
@@ -144,6 +179,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
iv_tag_size = 8;
|
||||
else if (!strcmp(cipher_mode, "ctr-random"))
|
||||
iv_tag_size = 16;
|
||||
else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 32;
|
||||
else if (!strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 16;
|
||||
|
||||
@@ -154,6 +191,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
auth_tag_size = 16; //FIXME gcm- mode only
|
||||
else if (!strcmp(integrity, "cmac(aes)"))
|
||||
auth_tag_size = 16;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
auth_tag_size = 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
auth_tag_size = 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -167,60 +206,98 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
return iv_tag_size + auth_tag_size;
|
||||
}
|
||||
|
||||
int INTEGRITY_create_dmd_device(struct crypt_device *cd,
|
||||
const struct crypt_params_integrity *params,
|
||||
struct volume_key *vk,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t flags, uint32_t sb_flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dmd)
|
||||
return -EINVAL;
|
||||
|
||||
*dmd = (struct crypt_dm_active_device) {
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
/* Workaround for kernel dm-integrity table bug */
|
||||
if (sb_flags & SB_FLAG_RECALCULATING)
|
||||
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
|
||||
|
||||
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
|
||||
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
|
||||
crypt_metadata_device(cd), crypt_data_device(cd),
|
||||
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
|
||||
crypt_get_sector_size(cd), vk, journal_crypt_key,
|
||||
journal_mac_key, params);
|
||||
}
|
||||
|
||||
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *type,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t sb_flags)
|
||||
{
|
||||
int r;
|
||||
uint32_t dmi_flags;
|
||||
struct dm_target *tgt = &dmd->segment;
|
||||
|
||||
if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
|
||||
device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
|
||||
|
||||
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
|
||||
tgt->u.integrity.offset, NULL, &dmd->flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (tgt->u.integrity.meta_device) {
|
||||
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dm_create_device(cd, name, type, dmd);
|
||||
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel does not support dm-integrity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
|
||||
!(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
|
||||
log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int INTEGRITY_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const struct crypt_params_integrity *params,
|
||||
struct volume_key *vk,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key,
|
||||
uint32_t flags)
|
||||
uint32_t flags, uint32_t sb_flags)
|
||||
{
|
||||
uint32_t dmi_flags;
|
||||
struct crypt_dm_active_device dmdi = {
|
||||
.target = DM_INTEGRITY,
|
||||
.data_device = crypt_data_device(cd),
|
||||
.flags = flags,
|
||||
.u.integrity = {
|
||||
.offset = crypt_get_data_offset(cd),
|
||||
.tag_size = crypt_get_integrity_tag_size(cd),
|
||||
.sector_size = crypt_get_sector_size(cd),
|
||||
.vk = vk,
|
||||
.journal_crypt_key = journal_crypt_key,
|
||||
.journal_integrity_key = journal_mac_key,
|
||||
}
|
||||
};
|
||||
int r;
|
||||
struct crypt_dm_active_device dmd = {};
|
||||
int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
|
||||
journal_mac_key, &dmd, flags, sb_flags);
|
||||
|
||||
r = INTEGRITY_data_sectors(cd, dmdi.data_device,
|
||||
dmdi.u.integrity.offset * SECTOR_SIZE, &dmdi.size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (params) {
|
||||
dmdi.u.integrity.journal_size = params->journal_size;
|
||||
dmdi.u.integrity.journal_watermark = params->journal_watermark;
|
||||
dmdi.u.integrity.journal_commit_time = params->journal_commit_time;
|
||||
dmdi.u.integrity.interleave_sectors = params->interleave_sectors;
|
||||
dmdi.u.integrity.buffer_sectors = params->buffer_sectors;
|
||||
dmdi.u.integrity.integrity = params->integrity;
|
||||
dmdi.u.integrity.journal_integrity = params->journal_integrity;
|
||||
dmdi.u.integrity.journal_crypt = params->journal_crypt;
|
||||
}
|
||||
|
||||
log_dbg("Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
|
||||
device_path(dmdi.data_device), name, dmdi.u.integrity.tag_size, dmdi.size);
|
||||
|
||||
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL,
|
||||
dmdi.u.integrity.offset, NULL, &dmdi.flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dm_create_device(cd, name, "INTEGRITY", &dmdi, 0);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -232,49 +309,56 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
uint32_t dmi_flags;
|
||||
char tmp_name[64], tmp_uuid[40];
|
||||
struct crypt_dm_active_device dmdi = {
|
||||
.target = DM_INTEGRITY,
|
||||
.data_device = crypt_data_device(cd),
|
||||
.size = 8,
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
|
||||
.u.integrity = {
|
||||
.offset = crypt_get_data_offset(cd),
|
||||
.tag_size = crypt_get_integrity_tag_size(cd),
|
||||
.sector_size = crypt_get_sector_size(cd),
|
||||
.journal_crypt_key = journal_crypt_key,
|
||||
.journal_integrity_key = journal_mac_key,
|
||||
}
|
||||
};
|
||||
struct dm_target *tgt = &dmdi.segment;
|
||||
int r;
|
||||
uuid_t tmp_uuid_bin;
|
||||
|
||||
if (params) {
|
||||
dmdi.u.integrity.journal_size = params->journal_size;
|
||||
dmdi.u.integrity.journal_watermark = params->journal_watermark;
|
||||
dmdi.u.integrity.journal_commit_time = params->journal_commit_time;
|
||||
dmdi.u.integrity.interleave_sectors = params->interleave_sectors;
|
||||
dmdi.u.integrity.buffer_sectors = params->buffer_sectors;
|
||||
dmdi.u.integrity.journal_integrity = params->journal_integrity;
|
||||
dmdi.u.integrity.journal_crypt = params->journal_crypt;
|
||||
dmdi.u.integrity.integrity = params->integrity;
|
||||
}
|
||||
struct volume_key *vk = NULL;
|
||||
|
||||
uuid_generate(tmp_uuid_bin);
|
||||
uuid_unparse(tmp_uuid_bin, tmp_uuid);
|
||||
|
||||
snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
|
||||
|
||||
log_dbg("Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
|
||||
device_path(dmdi.data_device), tmp_name, dmdi.u.integrity.tag_size);
|
||||
/* There is no data area, we can actually use fake zeroed key */
|
||||
if (params && params->integrity_key_size)
|
||||
vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
|
||||
|
||||
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL, dmdi.u.integrity.offset, NULL, NULL);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (r)
|
||||
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
|
||||
crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
|
||||
crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
|
||||
journal_crypt_key, journal_mac_key, params);
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(vk);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dm_create_device(cd, tmp_name, "INTEGRITY", &dmdi, 0);
|
||||
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
|
||||
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
|
||||
|
||||
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
|
||||
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel does not support dm-integrity mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmdi);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (tgt->u.integrity.meta_device) {
|
||||
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmdi);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
|
||||
crypt_free_volume_key(vk);
|
||||
dm_targets_free(cd, &dmdi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity header defitinion
|
||||
* Integrity header definition
|
||||
*
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -27,10 +27,19 @@ struct crypt_device;
|
||||
struct device;
|
||||
struct crypt_params_integrity;
|
||||
struct volume_key;
|
||||
struct crypt_dm_active_device;
|
||||
|
||||
/* dm-integrity helper */
|
||||
#define SB_MAGIC "integrt"
|
||||
#define SB_VERSION 1
|
||||
#define SB_VERSION_1 1
|
||||
#define SB_VERSION_2 2
|
||||
#define SB_VERSION_3 3
|
||||
#define SB_VERSION_4 4
|
||||
|
||||
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
|
||||
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
|
||||
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
|
||||
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
|
||||
|
||||
struct superblock {
|
||||
uint8_t magic[8];
|
||||
@@ -41,19 +50,27 @@ struct superblock {
|
||||
uint64_t provided_data_sectors;
|
||||
uint32_t flags;
|
||||
uint8_t log2_sectors_per_block;
|
||||
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
|
||||
uint8_t pad[2];
|
||||
uint64_t recalc_sector; /* V2 only */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd,
|
||||
struct crypt_params_integrity *params,
|
||||
uint32_t *flags);
|
||||
|
||||
int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset);
|
||||
|
||||
int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
struct device *device, uint64_t offset,
|
||||
uint64_t *data_sectors);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd,
|
||||
const char *integrity);
|
||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
const char *integrity,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
int INTEGRITY_hash_tag_size(const char *integrity);
|
||||
|
||||
int INTEGRITY_format(struct crypt_device *cd,
|
||||
const struct crypt_params_integrity *params,
|
||||
@@ -66,5 +83,19 @@ int INTEGRITY_activate(struct crypt_device *cd,
|
||||
struct volume_key *vk,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key,
|
||||
uint32_t flags);
|
||||
uint32_t flags, uint32_t sb_flags);
|
||||
|
||||
int INTEGRITY_create_dmd_device(struct crypt_device *cd,
|
||||
const struct crypt_params_integrity *params,
|
||||
struct volume_key *vk,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t flags, uint32_t sb_flags);
|
||||
|
||||
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *type,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t sb_flags);
|
||||
#endif
|
||||
|
||||
136
lib/internal.h
136
lib/internal.h
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* libcryptsetup - cryptsetup library internal
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -27,51 +27,81 @@
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "nls.h"
|
||||
#include "bitops.h"
|
||||
#include "utils_blkid.h"
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_loop.h"
|
||||
#include "utils_dm.h"
|
||||
#include "utils_fips.h"
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend.h"
|
||||
#include "utils_storage_wrappers.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
/* to silent gcc -Wcast-qual for const cast */
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
#define SHIFT_4K 12
|
||||
#define SECTOR_SHIFT 9
|
||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||
#define MAX_SECTOR_SIZE 4096 /* min page size among all platforms */
|
||||
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
|
||||
#define DEFAULT_MEM_ALIGNMENT 4096
|
||||
#define MAX_ERROR_LENGTH 512
|
||||
#define LOG_MAX_LEN 4096
|
||||
#define MAX_DM_DEPS 32
|
||||
|
||||
#define MAX_PBKDF_THREADS 4
|
||||
#define MAX_PBKDF_MEMORY 1024*1024 /* 1GiB */
|
||||
#define MIN_PBKDF2_ITERATIONS 1000 /* recommendation in NIST SP 800-132 */
|
||||
#define CRYPT_SUBDEV "SUBDEV" /* prefix for sublayered devices underneath public crypt types */
|
||||
|
||||
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
|
||||
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#define MISALIGNED(a, b) ((a) & ((b) - 1))
|
||||
#define MISALIGNED_4K(a) MISALIGNED((a), 1 << SHIFT_4K)
|
||||
#define MISALIGNED_512(a) MISALIGNED((a), 1 << SECTOR_SHIFT)
|
||||
#define NOTPOW2(a) MISALIGNED((a), (a))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#define MOVE_REF(x, y) \
|
||||
do { \
|
||||
typeof (x) *_px = &(x), *_py = &(y); \
|
||||
*_px = *_py; \
|
||||
*_py = NULL; \
|
||||
} while (0)
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
struct crypt_device;
|
||||
struct luks2_reenc_context;
|
||||
|
||||
struct volume_key {
|
||||
int id;
|
||||
size_t keylength;
|
||||
const char *key_description;
|
||||
struct volume_key *next;
|
||||
char key[];
|
||||
};
|
||||
|
||||
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
|
||||
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
|
||||
void crypt_free_volume_key(struct volume_key *vk);
|
||||
void crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
|
||||
const char *crypt_volume_key_get_description(const struct volume_key *key);
|
||||
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
|
||||
void crypt_volume_key_set_id(struct volume_key *vk, int id);
|
||||
int crypt_volume_key_get_id(const struct volume_key *vk);
|
||||
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
|
||||
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
|
||||
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
|
||||
|
||||
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
|
||||
int init_pbkdf_type(struct crypt_device *cd,
|
||||
@@ -82,37 +112,47 @@ int verify_pbkdf_params(struct crypt_device *cd,
|
||||
int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
struct crypt_pbkdf_type *pbkdf,
|
||||
size_t volume_key_size);
|
||||
const char *crypt_get_cipher_spec(struct crypt_device *cd);
|
||||
|
||||
/* Device backend */
|
||||
struct device;
|
||||
int device_alloc(struct device **device, const char *path);
|
||||
int device_alloc(struct crypt_device *cd, struct device **device, const char *path);
|
||||
int device_alloc_no_check(struct device **device, const char *path);
|
||||
void device_free(struct device *device);
|
||||
void device_close(struct crypt_device *cd, struct device *device);
|
||||
void device_free(struct crypt_device *cd, struct device *device);
|
||||
const char *device_path(const struct device *device);
|
||||
const char *device_dm_name(const struct device *device);
|
||||
const char *device_block_path(const struct device *device);
|
||||
void device_topology_alignment(struct device *device,
|
||||
unsigned long *required_alignment, /* bytes */
|
||||
unsigned long *alignment_offset, /* bytes */
|
||||
unsigned long default_alignment);
|
||||
size_t device_block_size(struct device *device);
|
||||
void device_topology_alignment(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
unsigned long *required_alignment, /* bytes */
|
||||
unsigned long *alignment_offset, /* bytes */
|
||||
unsigned long default_alignment);
|
||||
size_t device_block_size(struct crypt_device *cd, struct device *device);
|
||||
int device_read_ahead(struct device *device, uint32_t *read_ahead);
|
||||
int device_size(struct device *device, uint64_t *size);
|
||||
int device_open(struct device *device, int flags);
|
||||
int device_open(struct crypt_device *cd, struct device *device, int flags);
|
||||
int device_open_excl(struct crypt_device *cd, struct device *device, int flags);
|
||||
void device_release_excl(struct crypt_device *cd, struct device *device);
|
||||
void device_disable_direct_io(struct device *device);
|
||||
int device_is_identical(struct device *device1, struct device *device2);
|
||||
int device_is_rotational(struct device *device);
|
||||
size_t device_alignment(struct device *device);
|
||||
int device_direct_io(const struct device *device);
|
||||
int device_fallocate(struct device *device, uint64_t size);
|
||||
void device_sync(struct crypt_device *cd, struct device *device);
|
||||
int device_check_size(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
uint64_t req_offset, int falloc);
|
||||
|
||||
int device_open_locked(struct device *device, int flags);
|
||||
int device_open_locked(struct crypt_device *cd, struct device *device, int flags);
|
||||
int device_read_lock(struct crypt_device *cd, struct device *device);
|
||||
int device_write_lock(struct crypt_device *cd, struct device *device);
|
||||
void device_read_unlock(struct device *device);
|
||||
void device_write_unlock(struct device *device);
|
||||
void device_read_unlock(struct crypt_device *cd, struct device *device);
|
||||
void device_write_unlock(struct crypt_device *cd, struct device *device);
|
||||
bool device_is_locked(struct device *device);
|
||||
|
||||
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
|
||||
enum devcheck { DEV_OK = 0, DEV_EXCL = 1 };
|
||||
int device_check_access(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
enum devcheck device_check);
|
||||
@@ -124,6 +164,13 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
uint32_t *flags);
|
||||
size_t size_round_up(size_t size, size_t block);
|
||||
|
||||
int create_or_reload_device(struct crypt_device *cd, const char *name,
|
||||
const char *type, struct crypt_dm_active_device *dmd);
|
||||
|
||||
int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *name,
|
||||
const char *type, struct crypt_dm_active_device *dmd,
|
||||
struct crypt_dm_active_device *dmdi);
|
||||
|
||||
/* Receive backend devices from context helpers */
|
||||
struct device *crypt_metadata_device(struct crypt_device *cd);
|
||||
struct device *crypt_data_device(struct crypt_device *cd);
|
||||
@@ -138,23 +185,16 @@ char *crypt_get_base_device(const char *dev_path);
|
||||
uint64_t crypt_dev_partition_offset(const char *dev_path);
|
||||
int lookup_by_disk_id(const char *dm_uuid);
|
||||
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t count);
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count);
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment, void *orig_buf, size_t count);
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count);
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
uint64_t crypt_getphysmemory_kb(void);
|
||||
|
||||
int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
const char *uint64_to_str(char *buffer, size_t size, const uint64_t *val);
|
||||
|
||||
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
void logger(struct crypt_device *cd, int level, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
#define log_dbg(c, x...) logger(c, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
#define log_std(c, x...) logger(c, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
#define log_verbose(c, x...) logger(c, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
|
||||
#define log_err(c, x...) logger(c, CRYPT_LOG_ERROR, __FILE__, __LINE__, x)
|
||||
@@ -171,7 +211,7 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
|
||||
void crypt_random_exit(void);
|
||||
int crypt_random_default_key_rng(void);
|
||||
|
||||
int crypt_plain_hash(struct crypt_device *ctx,
|
||||
int crypt_plain_hash(struct crypt_device *cd,
|
||||
const char *hash_name,
|
||||
char *key, size_t key_size,
|
||||
const char *passphrase, size_t passphrase_size);
|
||||
@@ -182,6 +222,11 @@ int PLAIN_activate(struct crypt_device *cd,
|
||||
uint32_t flags);
|
||||
|
||||
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
|
||||
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd);
|
||||
|
||||
int onlyLUKS2(struct crypt_device *cd);
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
|
||||
|
||||
int crypt_wipe_device(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
@@ -199,5 +244,26 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
|
||||
|
||||
int crypt_key_in_keyring(struct crypt_device *cd);
|
||||
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
int crypt_use_keyring_for_vk(struct crypt_device *cd);
|
||||
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
|
||||
|
||||
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
|
||||
{
|
||||
return (uint64_t)release | ((uint64_t)patch << 16) | ((uint64_t)minor << 32) | ((uint64_t)major << 48);
|
||||
}
|
||||
|
||||
int kernel_version(uint64_t *kversion);
|
||||
|
||||
int crypt_serialize_lock(struct crypt_device *cd);
|
||||
void crypt_serialize_unlock(struct crypt_device *cd);
|
||||
|
||||
bool crypt_string_in(const char *str, char **list, size_t list_size);
|
||||
int crypt_strcmp(const char *a, const char *b);
|
||||
int crypt_compare_dm_devices(struct crypt_device *cd,
|
||||
const struct crypt_dm_active_device *src,
|
||||
const struct crypt_dm_active_device *tgt);
|
||||
static inline void *crypt_zalloc(size_t size) { return calloc(1, size); }
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
CRYPTSETUP_2.0 {
|
||||
global:
|
||||
crypt_init;
|
||||
crypt_init_data_device;
|
||||
crypt_init_by_name;
|
||||
crypt_init_by_name_and_header;
|
||||
|
||||
@@ -11,6 +12,9 @@ CRYPTSETUP_2.0 {
|
||||
crypt_set_label;
|
||||
crypt_set_data_device;
|
||||
|
||||
crypt_set_compatibility;
|
||||
crypt_get_compatibility;
|
||||
|
||||
crypt_memory_lock;
|
||||
crypt_metadata_locking;
|
||||
crypt_format;
|
||||
@@ -22,12 +26,15 @@ CRYPTSETUP_2.0 {
|
||||
crypt_resume_by_passphrase;
|
||||
crypt_resume_by_keyfile;
|
||||
crypt_resume_by_keyfile_offset;
|
||||
crypt_resume_by_keyfile_device_offset;
|
||||
crypt_resume_by_volume_key;
|
||||
crypt_free;
|
||||
|
||||
crypt_keyslot_add_by_passphrase;
|
||||
crypt_keyslot_change_by_passphrase;
|
||||
crypt_keyslot_add_by_keyfile;
|
||||
crypt_keyslot_add_by_keyfile_offset;
|
||||
crypt_keyslot_add_by_keyfile_device_offset;
|
||||
crypt_keyslot_add_by_volume_key;
|
||||
crypt_keyslot_add_by_key;
|
||||
|
||||
@@ -41,6 +48,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_token_luks2_keyring_set;
|
||||
crypt_token_assign_keyslot;
|
||||
crypt_token_unassign_keyslot;
|
||||
crypt_token_is_assigned;
|
||||
crypt_token_register;
|
||||
|
||||
crypt_activate_by_token;
|
||||
@@ -49,7 +57,9 @@ CRYPTSETUP_2.0 {
|
||||
crypt_activate_by_passphrase;
|
||||
crypt_activate_by_keyfile;
|
||||
crypt_activate_by_keyfile_offset;
|
||||
crypt_activate_by_keyfile_device_offset;
|
||||
crypt_activate_by_volume_key;
|
||||
crypt_activate_by_signed_key;
|
||||
crypt_activate_by_keyring;
|
||||
crypt_deactivate;
|
||||
crypt_deactivate_by_name;
|
||||
@@ -64,15 +74,21 @@ CRYPTSETUP_2.0 {
|
||||
crypt_get_cipher_mode;
|
||||
crypt_get_integrity_info;
|
||||
crypt_get_uuid;
|
||||
crypt_set_data_offset;
|
||||
crypt_get_data_offset;
|
||||
crypt_get_iv_offset;
|
||||
crypt_get_volume_key_size;
|
||||
crypt_get_device_name;
|
||||
crypt_get_metadata_device_name;
|
||||
crypt_get_metadata_size;
|
||||
crypt_set_metadata_size;
|
||||
crypt_get_verity_info;
|
||||
crypt_get_sector_size;
|
||||
|
||||
crypt_get_type;
|
||||
crypt_get_default_type;
|
||||
crypt_get_active_device;
|
||||
crypt_get_active_integrity_failures;
|
||||
crypt_persistent_flags_set;
|
||||
crypt_persistent_flags_get;
|
||||
|
||||
@@ -80,10 +96,17 @@ CRYPTSETUP_2.0 {
|
||||
crypt_get_rng_type;
|
||||
crypt_set_pbkdf_type;
|
||||
crypt_get_pbkdf_type;
|
||||
crypt_get_pbkdf_type_params;
|
||||
crypt_get_pbkdf_default;
|
||||
|
||||
crypt_keyslot_max;
|
||||
crypt_keyslot_area;
|
||||
crypt_keyslot_status;
|
||||
crypt_keyslot_get_key_size;
|
||||
crypt_keyslot_set_encryption;
|
||||
crypt_keyslot_get_encryption;
|
||||
crypt_keyslot_get_pbkdf;
|
||||
|
||||
crypt_get_dir;
|
||||
crypt_set_debug_level;
|
||||
crypt_log;
|
||||
@@ -92,8 +115,19 @@ CRYPTSETUP_2.0 {
|
||||
crypt_header_restore;
|
||||
|
||||
crypt_keyfile_read;
|
||||
crypt_keyfile_device_read;
|
||||
|
||||
crypt_wipe;
|
||||
|
||||
crypt_reencrypt_init_by_passphrase;
|
||||
crypt_reencrypt_init_by_keyring;
|
||||
crypt_reencrypt;
|
||||
crypt_reencrypt_status;
|
||||
|
||||
crypt_safe_alloc;
|
||||
crypt_safe_realloc;
|
||||
crypt_safe_free;
|
||||
crypt_safe_memzero;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
1797
lib/libdevmapper.c
1797
lib/libdevmapper.c
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -81,18 +81,18 @@ static int hash_keys(struct crypt_device *cd,
|
||||
const char *hash_name;
|
||||
char tweak, *key_ptr;
|
||||
unsigned int i;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
hash_name = hash_override ?: get_hash(key_len_output);
|
||||
tweak = get_tweak(keys_count);
|
||||
|
||||
if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
|
||||
log_err(cd, _("Key processing error (using hash %s).\n"),
|
||||
log_err(cd, _("Key processing error (using hash %s)."),
|
||||
hash_name ?: "[none]");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_len_output * keys_count, NULL);
|
||||
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -137,13 +137,13 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
unsigned int key_lengths[LOOPAES_KEYS_MAX];
|
||||
unsigned int i, key_index, key_len, offset;
|
||||
|
||||
log_dbg("Parsing loop-AES keyfile of size %zu.", buffer_len);
|
||||
log_dbg(cd, "Parsing loop-AES keyfile of size %zu.", buffer_len);
|
||||
|
||||
if (!buffer_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (keyfile_is_gpg(buffer, buffer_len)) {
|
||||
log_err(cd, _("Detected not yet supported GPG encrypted keyfile.\n"));
|
||||
log_err(cd, _("Detected not yet supported GPG encrypted keyfile."));
|
||||
log_std(cd, _("Please use gpg --decrypt <KEYFILE> | cryptsetup --keyfile=- ...\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -164,8 +164,8 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
key_lengths[key_index]++;
|
||||
}
|
||||
if (offset == buffer_len) {
|
||||
log_dbg("Unterminated key #%d in keyfile.", key_index);
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_dbg(cd, "Unterminated key #%d in keyfile.", key_index);
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
while (offset < buffer_len && !buffer[offset])
|
||||
@@ -177,7 +177,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
key_len = key_lengths[0];
|
||||
for (i = 0; i < key_index; i++)
|
||||
if (!key_lengths[i] || (key_lengths[i] != key_len)) {
|
||||
log_dbg("Unexpected length %d of key #%d (should be %d).",
|
||||
log_dbg(cd, "Unexpected length %d of key #%d (should be %d).",
|
||||
key_lengths[i], i, key_len);
|
||||
key_len = 0;
|
||||
break;
|
||||
@@ -185,11 +185,11 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
|
||||
if (offset != buffer_len || key_len == 0 ||
|
||||
(key_index != 1 && key_index !=64 && key_index != 65)) {
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg("Keyfile: %d keys of length %d.", key_index, key_len);
|
||||
log_dbg(cd, "Keyfile: %d keys of length %d.", key_index, key_len);
|
||||
|
||||
*keys_count = key_index;
|
||||
return hash_keys(cd, vk, hash, keys, key_index,
|
||||
@@ -203,25 +203,15 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags)
|
||||
{
|
||||
char *cipher = NULL;
|
||||
uint32_t req_flags, dmc_flags;
|
||||
int r;
|
||||
uint32_t req_flags, dmc_flags;
|
||||
char *cipher = NULL;
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.target = DM_CRYPT,
|
||||
.size = 0,
|
||||
.flags = flags,
|
||||
.data_device = crypt_data_device(cd),
|
||||
.u.crypt = {
|
||||
.cipher = NULL,
|
||||
.vk = vk,
|
||||
.offset = crypt_get_data_offset(cd),
|
||||
.iv_offset = crypt_get_iv_offset(cd),
|
||||
.sector_size = crypt_get_sector_size(cd),
|
||||
}
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
|
||||
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
|
||||
r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL,
|
||||
crypt_get_data_offset(cd), &dmd.size, &dmd.flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -235,18 +225,29 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
dmd.u.crypt.cipher = cipher;
|
||||
log_dbg("Trying to activate loop-AES device %s using cipher %s.",
|
||||
name, dmd.u.crypt.cipher);
|
||||
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
|
||||
vk, cipher, crypt_get_iv_offset(cd),
|
||||
crypt_get_data_offset(cd), crypt_get_integrity(cd),
|
||||
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
|
||||
|
||||
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
|
||||
if (r) {
|
||||
free(cipher);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
|
||||
log_dbg(cd, "Trying to activate loop-AES device %s using cipher %s.",
|
||||
name, cipher);
|
||||
|
||||
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd);
|
||||
|
||||
if (r < 0 && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
|
||||
(dmc_flags & req_flags) != req_flags) {
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
|
||||
log_err(cd, _("Kernel does not support loop-AES compatible mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
free(cipher);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2020 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,6 +22,7 @@
|
||||
#ifndef _LOOPAES_H
|
||||
#define _LOOPAES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct crypt_device;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include "internal.h"
|
||||
#include "af.h"
|
||||
@@ -34,7 +33,7 @@ static void XORblock(const char *src1, const char *src2, char *dst, size_t n)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
for(j = 0; j < n; ++j)
|
||||
for (j = 0; j < n; j++)
|
||||
dst[j] = src1[j] ^ src2[j];
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ static int hash_buf(const char *src, char *dst, uint32_t iv,
|
||||
char *iv_char = (char *)&iv;
|
||||
int r;
|
||||
|
||||
iv = htonl(iv);
|
||||
iv = be32_to_cpu(iv);
|
||||
if (crypt_hash_init(&hd, hash_name))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -61,34 +60,38 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* diffuse: Information spreading over the whole dataset with
|
||||
/*
|
||||
* diffuse: Information spreading over the whole dataset with
|
||||
* the help of hash function.
|
||||
*/
|
||||
|
||||
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
|
||||
{
|
||||
int hash_size = crypt_hash_size(hash_name);
|
||||
int r, hash_size = crypt_hash_size(hash_name);
|
||||
unsigned int digest_size;
|
||||
unsigned int i, blocks, padding;
|
||||
|
||||
if (hash_size <= 0)
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
digest_size = hash_size;
|
||||
|
||||
blocks = size / digest_size;
|
||||
padding = size % digest_size;
|
||||
|
||||
for (i = 0; i < blocks; i++)
|
||||
if(hash_buf(src + digest_size * i,
|
||||
for (i = 0; i < blocks; i++) {
|
||||
r = hash_buf(src + digest_size * i,
|
||||
dst + digest_size * i,
|
||||
i, (size_t)digest_size, hash_name))
|
||||
return 1;
|
||||
i, (size_t)digest_size, hash_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if(padding)
|
||||
if(hash_buf(src + digest_size * i,
|
||||
if (padding) {
|
||||
r = hash_buf(src + digest_size * i,
|
||||
dst + digest_size * i,
|
||||
i, (size_t)padding, hash_name))
|
||||
return 1;
|
||||
i, (size_t)padding, hash_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -98,53 +101,57 @@ static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
|
||||
* blocknumbers. The same blocksize and blocknumbers values
|
||||
* must be supplied to AF_merge to recover information.
|
||||
*/
|
||||
|
||||
int AF_split(const char *src, char *dst, size_t blocksize,
|
||||
unsigned int blocknumbers, const char *hash)
|
||||
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
|
||||
size_t blocksize, unsigned int blocknumbers, const char *hash)
|
||||
{
|
||||
unsigned int i;
|
||||
char *bufblock;
|
||||
int r = -EINVAL;
|
||||
int r;
|
||||
|
||||
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
|
||||
bufblock = crypt_safe_alloc(blocksize);
|
||||
if (!bufblock)
|
||||
return -ENOMEM;
|
||||
|
||||
/* process everything except the last block */
|
||||
for(i=0; i<blocknumbers-1; i++) {
|
||||
r = crypt_random_get(NULL, dst+(blocksize*i), blocksize, CRYPT_RND_NORMAL);
|
||||
if(r < 0) goto out;
|
||||
for (i = 0; i < blocknumbers - 1; i++) {
|
||||
r = crypt_random_get(ctx, dst + blocksize * i, blocksize, CRYPT_RND_NORMAL);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
XORblock(dst+(blocksize*i),bufblock,bufblock,blocksize);
|
||||
if(diffuse(bufblock, bufblock, blocksize, hash))
|
||||
XORblock(dst + blocksize * i, bufblock, bufblock, blocksize);
|
||||
r = diffuse(bufblock, bufblock, blocksize, hash);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
/* the last block is computed */
|
||||
XORblock(src,bufblock,dst+(i*blocksize),blocksize);
|
||||
XORblock(src, bufblock, dst + blocksize * i, blocksize);
|
||||
r = 0;
|
||||
out:
|
||||
free(bufblock);
|
||||
crypt_safe_free(bufblock);
|
||||
return r;
|
||||
}
|
||||
|
||||
int AF_merge(const char *src, char *dst, size_t blocksize,
|
||||
unsigned int blocknumbers, const char *hash)
|
||||
int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src, char *dst,
|
||||
size_t blocksize, unsigned int blocknumbers, const char *hash)
|
||||
{
|
||||
unsigned int i;
|
||||
char *bufblock;
|
||||
int r = -EINVAL;
|
||||
int r;
|
||||
|
||||
if((bufblock = calloc(blocksize, 1)) == NULL)
|
||||
bufblock = crypt_safe_alloc(blocksize);
|
||||
if (!bufblock)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(bufblock,0,blocksize);
|
||||
for(i=0; i<blocknumbers-1; i++) {
|
||||
XORblock(src+(blocksize*i),bufblock,bufblock,blocksize);
|
||||
if(diffuse(bufblock, bufblock, blocksize, hash))
|
||||
for(i = 0; i < blocknumbers - 1; i++) {
|
||||
XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
|
||||
r = diffuse(bufblock, bufblock, blocksize, hash);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
XORblock(src + blocksize * i, bufblock, dst, blocksize);
|
||||
r = 0;
|
||||
out:
|
||||
free(bufblock);
|
||||
crypt_safe_free(bufblock);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
#define INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* AF_split operates on src and produces information split data in
|
||||
* dst. src is assumed to be of the length blocksize. The data stripe
|
||||
@@ -37,8 +39,10 @@
|
||||
* On error, both functions return -1, 0 otherwise.
|
||||
*/
|
||||
|
||||
int AF_split(const char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
|
||||
int AF_merge(const char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
|
||||
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
|
||||
size_t blocksize, unsigned int blocknumbers, const char *hash);
|
||||
int AF_merge(struct crypt_device *ctx, const char *src, char *dst, size_t blocksize,
|
||||
unsigned int blocknumbers, const char *hash);
|
||||
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers);
|
||||
|
||||
int LUKS_encrypt_to_storage(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "luks.h"
|
||||
#include "af.h"
|
||||
#include "internal.h"
|
||||
@@ -30,17 +31,19 @@
|
||||
static void _error_hint(struct crypt_device *ctx, const char *device,
|
||||
const char *cipher, const char *mode, size_t keyLength)
|
||||
{
|
||||
char cipher_spec[MAX_CIPHER_LEN * 3];
|
||||
char *c, cipher_spec[MAX_CIPHER_LEN * 3];
|
||||
|
||||
if (snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", cipher, mode) < 0)
|
||||
return;
|
||||
|
||||
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
|
||||
"Check that kernel supports %s cipher (check syslog for more info).\n"),
|
||||
"Check that kernel supports %s cipher (check syslog for more info)."),
|
||||
device, cipher_spec);
|
||||
|
||||
if (!strncmp(mode, "xts", 3) && (keyLength != 256 && keyLength != 512))
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits.\n"));
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits."));
|
||||
else if (!(c = strchr(mode, '-')) || strlen(c) < 4)
|
||||
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format."));
|
||||
}
|
||||
|
||||
static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
@@ -54,29 +57,23 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
char name[PATH_MAX], path[PATH_MAX];
|
||||
char cipher_spec[MAX_CIPHER_LEN * 3];
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.target = DM_CRYPT,
|
||||
.uuid = NULL,
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE,
|
||||
.data_device = crypt_metadata_device(ctx),
|
||||
.u.crypt = {
|
||||
.cipher = cipher_spec,
|
||||
.vk = vk,
|
||||
.offset = sector,
|
||||
.iv_offset = 0,
|
||||
.sector_size = SECTOR_SIZE,
|
||||
}
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE,
|
||||
};
|
||||
int r, devfd = -1;
|
||||
size_t bsize, alignment;
|
||||
int r, devfd = -1, remove_dev = 0;
|
||||
size_t bsize, keyslot_alignment, alignment;
|
||||
|
||||
log_dbg("Using dmcrypt to access keyslot area.");
|
||||
log_dbg(ctx, "Using dmcrypt to access keyslot area.");
|
||||
|
||||
bsize = device_block_size(dmd.data_device);
|
||||
alignment = device_alignment(dmd.data_device);
|
||||
bsize = device_block_size(ctx, crypt_metadata_device(ctx));
|
||||
alignment = device_alignment(crypt_metadata_device(ctx));
|
||||
if (!bsize || !alignment)
|
||||
return -EINVAL;
|
||||
|
||||
dmd.size = size_round_up(srcLength, bsize) / SECTOR_SIZE;
|
||||
if (bsize > LUKS_ALIGN_KEYSLOTS)
|
||||
keyslot_alignment = LUKS_ALIGN_KEYSLOTS;
|
||||
else
|
||||
keyslot_alignment = bsize;
|
||||
dmd.size = size_round_up(srcLength, keyslot_alignment) / SECTOR_SIZE;
|
||||
|
||||
if (mode == O_RDONLY)
|
||||
dmd.flags |= CRYPT_ACTIVATE_READONLY;
|
||||
@@ -88,45 +85,55 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
if (snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", cipher, cipher_mode) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
|
||||
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
|
||||
r = device_block_adjust(ctx, crypt_metadata_device(ctx), DEV_OK,
|
||||
sector, &dmd.size, &dmd.flags);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Device %s doesn't exist or access denied.\n"),
|
||||
device_path(dmd.data_device));
|
||||
log_err(ctx, _("Device %s does not exist or access denied."),
|
||||
device_path(crypt_metadata_device(ctx)));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
device_path(dmd.data_device));
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(crypt_metadata_device(ctx)));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
r = dm_create_device(ctx, name, "TEMP", &dmd, 0);
|
||||
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
|
||||
crypt_metadata_device(ctx), vk, cipher_spec, 0, sector,
|
||||
NULL, 0, SECTOR_SIZE);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = dm_create_device(ctx, name, "TEMP", &dmd);
|
||||
if (r < 0) {
|
||||
if (r != -EACCES && r != -ENOTSUP)
|
||||
_error_hint(ctx, device_path(dmd.data_device),
|
||||
_error_hint(ctx, device_path(crypt_metadata_device(ctx)),
|
||||
cipher, cipher_mode, vk->keylength * 8);
|
||||
return -EIO;
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
remove_dev = 1;
|
||||
|
||||
devfd = open(path, mode | O_DIRECT | O_SYNC);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Failed to open temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to open temporary keystore device."));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = func(devfd, bsize, alignment, src, srcLength);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Failed to access temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to access temporary keystore device."));
|
||||
r = -EIO;
|
||||
} else
|
||||
r = 0;
|
||||
out:
|
||||
dm_targets_free(ctx, &dmd);
|
||||
if (devfd != -1)
|
||||
close(devfd);
|
||||
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
|
||||
if (remove_dev)
|
||||
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -137,20 +144,19 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r = 0;
|
||||
int devfd, r = 0;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (srcLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
|
||||
if (r)
|
||||
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
|
||||
/* Fallback to old temporary dmcrypt device */
|
||||
@@ -164,9 +170,9 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
return r;
|
||||
}
|
||||
|
||||
log_dbg("Using userspace crypto wrapper to access keyslot area.");
|
||||
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
|
||||
r = crypt_storage_encrypt(s, 0, srcLength, src);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
if (r)
|
||||
@@ -175,21 +181,23 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
r = -EIO;
|
||||
|
||||
/* Write buffer to device */
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (device_is_locked(device))
|
||||
devfd = device_open_locked(ctx, device, O_RDWR);
|
||||
else
|
||||
devfd = device_open(ctx, device, O_RDWR);
|
||||
if (devfd < 0)
|
||||
goto out;
|
||||
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
write_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src, srcLength) == -1)
|
||||
if (write_lseek_blockwise(devfd, device_block_size(ctx, device),
|
||||
device_alignment(device), src, srcLength,
|
||||
sector * SECTOR_SIZE) < 0)
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
device_sync(ctx, device);
|
||||
if (r)
|
||||
log_err(ctx, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(ctx, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -203,16 +211,17 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
{
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r = 0;
|
||||
struct stat st;
|
||||
int devfd, r = 0;
|
||||
|
||||
/* Only whole sector reads supported */
|
||||
if (dstLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
|
||||
if (r)
|
||||
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
|
||||
/* Fallback to old temporary dmcrypt device */
|
||||
@@ -226,32 +235,33 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
return r;
|
||||
}
|
||||
|
||||
log_dbg("Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
r = -EIO;
|
||||
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
/* Read buffer from device */
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0)
|
||||
goto bad;
|
||||
if (device_is_locked(device))
|
||||
devfd = device_open_locked(ctx, device, O_RDONLY);
|
||||
else
|
||||
devfd = device_open(ctx, device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
crypt_storage_destroy(s);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
read_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst, dstLength) == -1)
|
||||
goto bad;
|
||||
if (read_lseek_blockwise(devfd, device_block_size(ctx, device),
|
||||
device_alignment(device), dst, dstLength,
|
||||
sector * SECTOR_SIZE) < 0) {
|
||||
if (!fstat(devfd, &st) && (st.st_size < (off_t)dstLength))
|
||||
log_err(ctx, _("Device %s is too small."), device_path(device));
|
||||
else
|
||||
log_err(ctx, _("IO error while decrypting keyslot."));
|
||||
|
||||
close(devfd);
|
||||
crypt_storage_destroy(s);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Decrypt buffer */
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
bad:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
|
||||
log_err(ctx, _("IO error while decrypting keyslot.\n"));
|
||||
r = crypt_storage_decrypt(s, 0, dstLength, dst);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -61,6 +61,9 @@
|
||||
/* Offset to keyslot area [in bytes] */
|
||||
#define LUKS_ALIGN_KEYSLOTS 4096
|
||||
|
||||
/* Maximal LUKS header size, for wipe [in bytes] */
|
||||
#define LUKS_MAX_KEYSLOT_SIZE 0x1000000 /* 16 MB, up to 32768 bits key */
|
||||
|
||||
/* Any integer values are stored in network byte order on disk and must be
|
||||
converted */
|
||||
|
||||
@@ -99,17 +102,20 @@ struct luks_phdr {
|
||||
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS_generate_phdr(
|
||||
struct luks_phdr *header,
|
||||
int LUKS_check_cipher(struct crypt_device *ctx,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
|
||||
int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
const struct volume_key *vk,
|
||||
const char *cipherName,
|
||||
const char *cipherMode,
|
||||
const char *hashSpec,
|
||||
const char *uuid,
|
||||
unsigned int stripes,
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
int detached_metadata_device,
|
||||
uint64_t data_offset,
|
||||
uint64_t align_offset,
|
||||
uint64_t required_alignment,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS_read_phdr(
|
||||
@@ -163,16 +169,22 @@ int LUKS_del_key(
|
||||
struct luks_phdr *hdr,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS_wipe_header_areas(struct luks_phdr *hdr,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot);
|
||||
int LUKS_keyslot_find_empty(struct luks_phdr *hdr);
|
||||
int LUKS_keyslot_active_count(struct luks_phdr *hdr);
|
||||
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable);
|
||||
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable,
|
||||
struct crypt_device *ctx);
|
||||
int LUKS_keyslot_area(const struct luks_phdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
size_t LUKS_device_sectors(const struct luks_phdr *hdr);
|
||||
size_t LUKS_keyslots_offset(const struct luks_phdr *hdr);
|
||||
int LUKS_keyslot_pbkdf(struct luks_phdr *hdr, int keyslot,
|
||||
struct crypt_pbkdf_type *pbkdf);
|
||||
|
||||
int LUKS1_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -22,7 +22,9 @@
|
||||
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
#define _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
||||
@@ -35,6 +37,7 @@
|
||||
|
||||
#define LUKS2_KEYSLOTS_MAX 32
|
||||
#define LUKS2_TOKENS_MAX 32
|
||||
#define LUKS2_SEGMENT_MAX 32
|
||||
|
||||
#define LUKS2_BUILTIN_TOKEN_PREFIX "luks2-"
|
||||
#define LUKS2_BUILTIN_TOKEN_PREFIX_LEN 6
|
||||
@@ -43,11 +46,19 @@
|
||||
|
||||
#define LUKS2_DIGEST_MAX 8
|
||||
|
||||
typedef int digests_t[LUKS2_DIGEST_MAX];
|
||||
|
||||
#define CRYPT_ANY_SEGMENT -1
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#define CRYPT_DEFAULT_SEGMENT_STR "0"
|
||||
#define CRYPT_DEFAULT_SEGMENT -2
|
||||
#define CRYPT_ONE_SEGMENT -3
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/* 20 MiBs */
|
||||
#define LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH 0x1400000
|
||||
|
||||
/* 1 GiB */
|
||||
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
|
||||
|
||||
struct device;
|
||||
|
||||
/*
|
||||
* LUKS2 header on-disk.
|
||||
@@ -97,6 +108,96 @@ struct luks2_hdr {
|
||||
json_object *jobj;
|
||||
};
|
||||
|
||||
struct luks2_keyslot_params {
|
||||
enum { LUKS2_KEYSLOT_AF_LUKS1 = 0 } af_type;
|
||||
enum { LUKS2_KEYSLOT_AREA_RAW = 0 } area_type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
|
||||
unsigned int stripes;
|
||||
} luks1;
|
||||
} af;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char encryption[65]; // or include utils_crypt.h
|
||||
size_t key_size;
|
||||
} raw;
|
||||
} area;
|
||||
};
|
||||
|
||||
struct reenc_protection {
|
||||
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
|
||||
REENC_PROTECTION_CHECKSUM,
|
||||
REENC_PROTECTION_JOURNAL,
|
||||
REENC_PROTECTION_DATASHIFT } type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
} none;
|
||||
struct {
|
||||
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
|
||||
struct crypt_hash *ch;
|
||||
size_t hash_size;
|
||||
/* buffer for checksums */
|
||||
void *checksums;
|
||||
size_t checksums_len;
|
||||
} csum;
|
||||
struct {
|
||||
} ds;
|
||||
} p;
|
||||
};
|
||||
|
||||
struct luks2_reenc_context {
|
||||
/* reencryption window attributes */
|
||||
uint64_t offset;
|
||||
uint64_t progress;
|
||||
uint64_t length;
|
||||
uint64_t data_shift;
|
||||
size_t alignment;
|
||||
uint64_t device_size;
|
||||
bool online;
|
||||
bool fixed_length;
|
||||
crypt_reencrypt_direction_info direction;
|
||||
crypt_reencrypt_mode_info mode;
|
||||
|
||||
char *device_name;
|
||||
char *hotzone_name;
|
||||
char *overlay_name;
|
||||
uint32_t flags;
|
||||
|
||||
/* reencryption window persistence attributes */
|
||||
struct reenc_protection rp;
|
||||
|
||||
int reenc_keyslot;
|
||||
|
||||
/* already running reencryption */
|
||||
json_object *jobj_segs_hot;
|
||||
json_object *jobj_segs_post;
|
||||
|
||||
/* backup segments */
|
||||
json_object *jobj_segment_new;
|
||||
int digest_new;
|
||||
json_object *jobj_segment_old;
|
||||
int digest_old;
|
||||
json_object *jobj_segment_moved;
|
||||
|
||||
struct volume_key *vks;
|
||||
|
||||
void *reenc_buffer;
|
||||
ssize_t read;
|
||||
|
||||
struct crypt_storage_wrapper *cw1;
|
||||
struct crypt_storage_wrapper *cw2;
|
||||
|
||||
uint32_t wflags1;
|
||||
uint32_t wflags2;
|
||||
|
||||
struct crypt_lock_handle *reenc_lock;
|
||||
};
|
||||
|
||||
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
|
||||
/*
|
||||
* Supportable header sizes (hdr_disk + JSON area)
|
||||
* Also used as offset for the 2nd header.
|
||||
@@ -105,15 +206,26 @@ struct luks2_hdr {
|
||||
|
||||
#define LUKS2_HDR_BIN_LEN sizeof(struct luks2_hdr_disk)
|
||||
|
||||
#define LUKS2_HDR_DEFAULT_LEN 0x400000 /* 4 MiB */
|
||||
//#define LUKS2_DEFAULT_HDR_SIZE 0x400000 /* 4 MiB */
|
||||
#define LUKS2_DEFAULT_HDR_SIZE 0x1000000 /* 16 MiB */
|
||||
|
||||
#define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */
|
||||
|
||||
#define LUKS2_HDR_OFFSET_MAX 0x400000 /* 4 MiB */
|
||||
|
||||
/* Offsets for secondary header (for scan if primary header is corrupted). */
|
||||
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
|
||||
0x40000, 0x080000, 0x100000, 0x200000, LUKS2_HDR_OFFSET_MAX }
|
||||
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
|
||||
const char *backup_file);
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_device_write_lock(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct device *device);
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
|
||||
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_hdr_uuid(struct crypt_device *cd,
|
||||
@@ -126,7 +238,7 @@ int LUKS2_hdr_labels(struct crypt_device *cd,
|
||||
const char *subsystem,
|
||||
int commit);
|
||||
|
||||
void LUKS2_hdr_free(struct luks2_hdr *hdr);
|
||||
void LUKS2_hdr_free(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_hdr_backup(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
@@ -137,6 +249,9 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
|
||||
|
||||
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
|
||||
uint64_t LUKS2_keyslots_size(json_object *jobj);
|
||||
uint64_t LUKS2_metadata_size(json_object *jobj);
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 keyslot
|
||||
@@ -148,12 +263,34 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
size_t password_len,
|
||||
struct volume_key **vk);
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks);
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
const struct volume_key *vk);
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
@@ -188,6 +325,11 @@ int LUKS2_token_assign(struct crypt_device *cd,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_token_is_assigned(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int token);
|
||||
|
||||
int LUKS2_token_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int token,
|
||||
@@ -224,43 +366,95 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
const char *name,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 segment
|
||||
*/
|
||||
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_type(json_object *jobj_segment);
|
||||
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
|
||||
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_get_cipher(json_object *jobj_segment);
|
||||
int json_segment_get_sector_size(json_object *jobj_segment);
|
||||
bool json_segment_is_backup(json_object *jobj_segment);
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
|
||||
unsigned json_segments_count(json_object *jobj_segments);
|
||||
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
|
||||
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
|
||||
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
|
||||
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
|
||||
|
||||
int LUKS2_segments_count(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
|
||||
|
||||
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
int LUKS2_segments_set(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
json_object *jobj_segments,
|
||||
int commit);
|
||||
|
||||
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 digest
|
||||
*/
|
||||
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk,
|
||||
digests_t digests);
|
||||
const struct volume_key *vk);
|
||||
|
||||
void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vk,
|
||||
const struct volume_key *vk,
|
||||
int keyslot);
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd,
|
||||
int digest);
|
||||
|
||||
int LUKS2_digest_json_get(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const char **json);
|
||||
|
||||
int LUKS2_digest_json_set(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const char *json);
|
||||
|
||||
int LUKS2_digests_assign(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_digest_assign(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -275,10 +469,7 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests);
|
||||
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot);
|
||||
|
||||
int LUKS2_digest_create(struct crypt_device *cd,
|
||||
const char *type,
|
||||
@@ -293,11 +484,25 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_keyslot_luks2_format(struct crypt_device *cd,
|
||||
int LUKS2_activate_multi(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint64_t device_size,
|
||||
uint32_t flags);
|
||||
|
||||
struct crypt_dm_active_device;
|
||||
|
||||
int LUKS2_deactivate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const char *cipher,
|
||||
size_t keylength);
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_reload(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint64_t device_size,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_generate_hdr(
|
||||
struct crypt_device *cd,
|
||||
@@ -308,24 +513,42 @@ int LUKS2_generate_hdr(
|
||||
const char *integrity,
|
||||
const char *uuid,
|
||||
unsigned int sector_size,
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
int detached_metadata_device);
|
||||
uint64_t data_offset,
|
||||
uint64_t align_offset,
|
||||
uint64_t required_alignment,
|
||||
uint64_t metadata_size,
|
||||
uint64_t keyslots_size);
|
||||
|
||||
int LUKS2_check_metadata_area_size(uint64_t metadata_size);
|
||||
int LUKS2_check_keyslots_area_size(uint64_t keyslots_size);
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
|
||||
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
|
||||
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
|
||||
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct luks2_keyslot_params *params);
|
||||
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_get_keyslot_key_size(struct luks2_hdr *hdr, int keyslot);
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
|
||||
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
|
||||
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
|
||||
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset);
|
||||
|
||||
/*
|
||||
* Permanent activation flags stored in header
|
||||
*/
|
||||
@@ -336,12 +559,16 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
|
||||
* Requirements for device activation or header modification
|
||||
*/
|
||||
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
|
||||
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs);
|
||||
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
|
||||
|
||||
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
|
||||
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
|
||||
|
||||
struct luks_phdr;
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
|
||||
@@ -351,4 +578,32 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr2,
|
||||
struct luks_phdr *hdr1);
|
||||
|
||||
/*
|
||||
* LUKS2 reencryption
|
||||
*/
|
||||
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags,
|
||||
struct volume_key **vks);
|
||||
|
||||
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks,
|
||||
json_object *jobj_segments,
|
||||
struct crypt_dm_active_device *dmd);
|
||||
|
||||
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd,
|
||||
struct crypt_params_reencrypt *params);
|
||||
|
||||
int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **reencrypt_lock);
|
||||
int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid, struct crypt_lock_handle **reencrypt_lock);
|
||||
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock);
|
||||
|
||||
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, digest handling
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -28,23 +28,7 @@ static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int crypt_digest_register(const digest_handler *handler)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digest_handlers[i]; i++) {
|
||||
if (!strcmp(digest_handlers[i]->name, handler->name))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i == LUKS2_DIGEST_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
digest_handlers[i] = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
|
||||
static const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -102,18 +86,14 @@ int LUKS2_digest_create(struct crypt_device *cd,
|
||||
if (digest < 0)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg("Creating new digest %d (%s).", digest, type);
|
||||
log_dbg(cd, "Creating new digest %d (%s).", digest, type);
|
||||
|
||||
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
|
||||
}
|
||||
|
||||
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests)
|
||||
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
char keyslot_name[16];
|
||||
int i = 0;
|
||||
json_object *jobj_digests, *jobj_digest_keyslots;
|
||||
|
||||
if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
|
||||
@@ -124,46 +104,47 @@ int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
|
||||
if (LUKS2_array_jobj(jobj_digest_keyslots, keyslot_name))
|
||||
digests[i++] = atoi(key);
|
||||
return atoi(key);
|
||||
}
|
||||
|
||||
if (i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
const digest_handler *h;
|
||||
int r;
|
||||
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vk,
|
||||
const struct volume_key *vk,
|
||||
int keyslot)
|
||||
{
|
||||
const digest_handler *h;
|
||||
digests_t digests;
|
||||
int i, r;
|
||||
int digest;
|
||||
|
||||
r = LUKS2_digests_by_keyslot(cd, hdr, keyslot, digests);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1 ; i++) {
|
||||
log_dbg("Verifying key from keyslot %d, digest %d.",
|
||||
keyslot, digests[i]);
|
||||
h = LUKS2_digest_handler(cd, digests[i]);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
|
||||
|
||||
r = h->verify(cd, digests[i], vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.",
|
||||
digests[i], h->name, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
|
||||
}
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
@@ -176,16 +157,35 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
return h->dump(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int digest;
|
||||
|
||||
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
|
||||
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
|
||||
return digest;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk,
|
||||
digests_t digests)
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
|
||||
}
|
||||
|
||||
/* FIXME: segment can have more digests */
|
||||
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
|
||||
{
|
||||
char segment_name[16];
|
||||
const digest_handler *h;
|
||||
json_object *jobj_digests, *jobj_digest_segments;
|
||||
int digest, r, i = 0;
|
||||
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT)
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
|
||||
@@ -197,41 +197,10 @@ int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
if (!LUKS2_array_jobj(jobj_digest_segments, segment_name))
|
||||
continue;
|
||||
|
||||
digest = atoi(key);
|
||||
log_dbg("Verifying key digest %d.", digest);
|
||||
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (digests)
|
||||
digests[i] = digest;
|
||||
i++;
|
||||
return atoi(key);
|
||||
}
|
||||
|
||||
if (digests && i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int digest, const char **json)
|
||||
{
|
||||
json_object *jobj_digest;
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
return -EINVAL;
|
||||
|
||||
*json = json_object_to_json_string_ext(jobj_digest, JSON_C_TO_STRING_PLAIN);
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
@@ -240,7 +209,7 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj1, *jobj_digest, *jobj_digest_keyslots;
|
||||
char num[16];
|
||||
|
||||
log_dbg("Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
|
||||
log_dbg(cd, "Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
@@ -264,20 +233,6 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_digests_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, digests_t digests, int assign, int commit)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1; i++) {
|
||||
r = LUKS2_digest_assign(cd, hdr, keyslot, digests[i], assign, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, int digest, int assign, int commit)
|
||||
{
|
||||
@@ -303,13 +258,43 @@ int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
static int assign_all_segments(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int digest, int assign)
|
||||
{
|
||||
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
|
||||
if (!jobj_digest_segments)
|
||||
return -EINVAL;
|
||||
|
||||
if (assign) {
|
||||
json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
|
||||
UNUSED(value);
|
||||
jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
|
||||
if (!jobj1)
|
||||
json_object_array_add(jobj_digest_segments, json_object_new_string(key));
|
||||
}
|
||||
} else {
|
||||
jobj1 = json_object_new_array();
|
||||
if (!jobj1)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_digest, "segments", jobj1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int segment, int digest, int assign)
|
||||
{
|
||||
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
|
||||
char num[16];
|
||||
|
||||
log_dbg("Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
|
||||
log_dbg(cd, "Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
@@ -339,17 +324,27 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj_digests;
|
||||
int r = 0;
|
||||
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT)
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
|
||||
if (digest == CRYPT_ANY_DIGEST) {
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
UNUSED(val);
|
||||
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
r = assign_all_segments(cd, hdr, atoi(key), assign);
|
||||
else
|
||||
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
|
||||
if (r < 0)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
r = assign_one_segment(cd, hdr, segment, digest, assign);
|
||||
} else {
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
r = assign_all_segments(cd, hdr, digest, assign);
|
||||
else
|
||||
r = assign_one_segment(cd, hdr, segment, digest, assign);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -363,14 +358,14 @@ static int digest_unused(json_object *jobj_digest)
|
||||
json_object *jobj;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj);
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj))
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj) > 0)
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "keyslots", &jobj);
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array))
|
||||
return 0;
|
||||
|
||||
return json_object_array_length(jobj) ? 0 : 1;
|
||||
return json_object_array_length(jobj) > 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
@@ -384,8 +379,77 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
if (digest_unused(val)) {
|
||||
log_dbg("Erasing unused digest %d.", atoi(key));
|
||||
log_dbg(cd, "Erasing unused digest %d.", atoi(key));
|
||||
json_object_object_del(jobj_digests, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Key description helpers */
|
||||
static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
{
|
||||
char *desc, digest_str[3];
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
if (!crypt_get_uuid(cd))
|
||||
return NULL;
|
||||
|
||||
r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
|
||||
if (r < 0 || (size_t)r >= sizeof(digest_str))
|
||||
return NULL;
|
||||
|
||||
/* "cryptsetup:<uuid>-<digest_str>" + \0 */
|
||||
len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
|
||||
|
||||
desc = malloc(len);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
|
||||
if (r < 0 || (size_t)r >= len) {
|
||||
free(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
|
||||
int r;
|
||||
|
||||
r = crypt_volume_key_set_description(vk, desc);
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(hdr, keyslot));
|
||||
int r;
|
||||
|
||||
r = crypt_volume_key_set_description(vk, desc);
|
||||
if (!r)
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, digest);
|
||||
int r;
|
||||
|
||||
r = crypt_volume_key_set_description(vk, desc);
|
||||
if (!r)
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -94,32 +94,48 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
json_object *jobj_digest, *jobj_digests;
|
||||
char salt[LUKS_SALTSIZE], digest_raw[128], num[16];
|
||||
int r;
|
||||
char salt[LUKS_SALTSIZE], digest_raw[128];
|
||||
int hmac_size, r;
|
||||
char *base64_str;
|
||||
struct luks2_hdr *hdr;
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
const struct crypt_pbkdf_type *pbkdf_cd;
|
||||
struct crypt_pbkdf_type pbkdf = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = "sha256",
|
||||
.time_ms = LUKS_MKD_ITERATIONS_MS,
|
||||
};
|
||||
|
||||
log_dbg("Setting PBKDF2 type key digest %d.", digest);
|
||||
/* Inherit hash from PBKDF setting */
|
||||
pbkdf_cd = crypt_get_pbkdf_type(cd);
|
||||
if (pbkdf_cd)
|
||||
pbkdf.hash = pbkdf_cd->hash;
|
||||
if (!pbkdf.hash)
|
||||
pbkdf.hash = DEFAULT_LUKS1_HASH;
|
||||
|
||||
log_dbg(cd, "Setting PBKDF2 type key digest %d.", digest);
|
||||
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
|
||||
pbkdf.iterations = MIN_PBKDF2_ITERATIONS;
|
||||
pbkdf.iterations = pbkdf_limits.min_iterations;
|
||||
else {
|
||||
r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
hmac_size = crypt_hmac_size(pbkdf.hash);
|
||||
if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
|
||||
salt, LUKS_SALTSIZE, digest_raw, crypt_hmac_size(pbkdf.hash),
|
||||
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
|
||||
pbkdf.iterations, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -146,7 +162,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
|
||||
free(base64_str);
|
||||
|
||||
base64_encode_alloc(digest_raw, crypt_hmac_size(pbkdf.hash), &base64_str);
|
||||
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
|
||||
if (!base64_str) {
|
||||
json_object_put(jobj_digest);
|
||||
return -ENOMEM;
|
||||
@@ -154,12 +170,10 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
|
||||
free(base64_str);
|
||||
|
||||
if (jobj_digests) {
|
||||
snprintf(num, sizeof(num), "%d", digest);
|
||||
json_object_object_add(jobj_digests, num, jobj_digest);
|
||||
}
|
||||
if (jobj_digests)
|
||||
json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
|
||||
|
||||
JSON_DBG(jobj_digest, "Digest JSON");
|
||||
JSON_DBG(cd, jobj_digest, "Digest JSON:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -26,34 +26,37 @@
|
||||
/*
|
||||
* Helper functions
|
||||
*/
|
||||
json_object *parse_json_len(const char *json_area, int length, int *end_offset)
|
||||
static json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
|
||||
uint64_t max_length, int *json_len)
|
||||
{
|
||||
json_object *jobj;
|
||||
struct json_tokener *jtok;
|
||||
|
||||
if (!json_area || length <= 0)
|
||||
/* INT32_MAX is internal (json-c) json_tokener_parse_ex() limit */
|
||||
if (!json_area || max_length > INT32_MAX)
|
||||
return NULL;
|
||||
|
||||
jtok = json_tokener_new();
|
||||
if (!jtok) {
|
||||
log_dbg("ERROR: Failed to init json tokener");
|
||||
log_dbg(cd, "ERROR: Failed to init json tokener");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobj = json_tokener_parse_ex(jtok, json_area, length);
|
||||
jobj = json_tokener_parse_ex(jtok, json_area, max_length);
|
||||
if (!jobj)
|
||||
log_dbg("ERROR: Failed to parse json data (%d): %s",
|
||||
log_dbg(cd, "ERROR: Failed to parse json data (%d): %s",
|
||||
json_tokener_get_error(jtok),
|
||||
json_tokener_error_desc(json_tokener_get_error(jtok)));
|
||||
else
|
||||
*end_offset = jtok->char_offset;
|
||||
*json_len = jtok->char_offset;
|
||||
|
||||
json_tokener_free(jtok);
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static void log_dbg_checksum(const uint8_t *csum, const char *csum_alg, const char *info)
|
||||
static void log_dbg_checksum(struct crypt_device *cd,
|
||||
const uint8_t *csum, const char *csum_alg, const char *info)
|
||||
{
|
||||
char csum_txt[2*LUKS2_CHECKSUM_L+1];
|
||||
int i;
|
||||
@@ -62,7 +65,7 @@ static void log_dbg_checksum(const uint8_t *csum, const char *csum_alg, const ch
|
||||
snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
|
||||
csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */
|
||||
|
||||
log_dbg("Checksum:%s (%s)", &csum_txt[0], info);
|
||||
log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,9 +77,10 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct crypt_hash *hd = NULL;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0 || crypt_hash_init(&hd, alg))
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0 || crypt_hash_init(&hd, alg))
|
||||
return -EINVAL;
|
||||
|
||||
/* Binary header, csum zeroed. */
|
||||
@@ -87,7 +91,7 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
r = crypt_hash_write(hd, json_area, json_len);
|
||||
|
||||
if (!r)
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, crypt_hash_size(alg));
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size);
|
||||
|
||||
crypt_hash_destroy(hd);
|
||||
return r;
|
||||
@@ -96,13 +100,15 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
/*
|
||||
* Compare hash (checksum) of on-disk and in-memory header.
|
||||
*/
|
||||
static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
static int hdr_checksum_check(struct crypt_device *cd,
|
||||
const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct luks2_hdr_disk hdr_tmp;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0)
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Copy header and zero checksum. */
|
||||
@@ -113,10 +119,10 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
|
||||
log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");
|
||||
log_dbg_checksum(cd, hdr_disk->csum, alg, "on-disk");
|
||||
log_dbg_checksum(cd, hdr_tmp.csum, alg, "in-memory");
|
||||
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, crypt_hash_size(alg)))
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -182,9 +188,10 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity checks before checkum is validated
|
||||
* Sanity checks before checksum is validated
|
||||
*/
|
||||
static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
|
||||
static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
|
||||
struct luks2_hdr_disk *hdr,
|
||||
size_t *hdr_json_size, int secondary,
|
||||
uint64_t offset)
|
||||
{
|
||||
@@ -192,19 +199,25 @@ static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
|
||||
return -EINVAL;
|
||||
|
||||
if (be16_to_cpu(hdr->version) != 2) {
|
||||
log_dbg("Unsupported LUKS2 header version %u.", be16_to_cpu(hdr->version));
|
||||
log_dbg(cd, "Unsupported LUKS2 header version %u.", be16_to_cpu(hdr->version));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset != be64_to_cpu(hdr->hdr_offset)) {
|
||||
log_dbg("LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
|
||||
log_dbg(cd, "LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
|
||||
(unsigned)be64_to_cpu(hdr->hdr_offset), (unsigned)offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
|
||||
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
|
||||
(unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* FIXME: sanity check checksum alg. */
|
||||
|
||||
log_dbg("LUKS2 header version %u of size %u bytes, checksum %s.",
|
||||
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
|
||||
(unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
|
||||
hdr->checksum_alg);
|
||||
|
||||
@@ -215,16 +228,17 @@ static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
|
||||
/*
|
||||
* Read LUKS2 header from disk at specific offset.
|
||||
*/
|
||||
static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
static int hdr_read_disk(struct crypt_device *cd,
|
||||
struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
char **json_area, uint64_t offset, int secondary)
|
||||
{
|
||||
size_t hdr_json_size = 0;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
log_dbg("Trying to read %s LUKS2 header at offset %" PRIu64 ".",
|
||||
log_dbg(cd, "Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
|
||||
secondary ? "secondary" : "primary", offset);
|
||||
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
devfd = device_open_locked(cd, device, O_RDONLY);
|
||||
if (devfd < 0)
|
||||
return devfd == -1 ? -EIO : devfd;
|
||||
|
||||
@@ -232,16 +246,14 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
* Read binary header and run sanity check before reading
|
||||
* JSON area and validating checksum.
|
||||
*/
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), hdr_disk,
|
||||
LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
r = hdr_disk_sanity_check_pre(hdr_disk, &hdr_json_size, secondary, offset);
|
||||
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
|
||||
if (r < 0) {
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -250,27 +262,23 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
*/
|
||||
*json_area = malloc(hdr_json_size);
|
||||
if (!*json_area) {
|
||||
close(devfd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), *json_area, hdr_json_size,
|
||||
offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) {
|
||||
close(devfd);
|
||||
free(*json_area);
|
||||
*json_area = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
|
||||
/*
|
||||
* Calculate and validate checksum and zero it afterwards.
|
||||
*/
|
||||
if (hdr_checksum_check(hdr_disk->checksum_alg, hdr_disk,
|
||||
if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk,
|
||||
*json_area, hdr_json_size)) {
|
||||
log_dbg("LUKS2 header checksum error (offset %" PRIu64 ").", offset);
|
||||
log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset);
|
||||
r = -EINVAL;
|
||||
}
|
||||
memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);
|
||||
@@ -281,20 +289,21 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
/*
|
||||
* Write LUKS2 header to disk at specific offset.
|
||||
*/
|
||||
static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
|
||||
const char *json_area, int secondary)
|
||||
static int hdr_write_disk(struct crypt_device *cd,
|
||||
struct device *device, struct luks2_hdr *hdr,
|
||||
const char *json_area, int secondary)
|
||||
{
|
||||
struct luks2_hdr_disk hdr_disk;
|
||||
uint64_t offset = secondary ? hdr->hdr_size : 0;
|
||||
size_t hdr_json_len;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
log_dbg("Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
|
||||
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
|
||||
hdr->hdr_size, offset);
|
||||
|
||||
/* FIXME: read-only device silent fail? */
|
||||
|
||||
devfd = device_open_locked(device, O_RDWR);
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd < 0)
|
||||
return devfd == -1 ? -EINVAL : devfd;
|
||||
|
||||
@@ -305,65 +314,84 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
|
||||
/*
|
||||
* Write header without checksum but with proper seqid.
|
||||
*/
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), (char *)&hdr_disk,
|
||||
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write json area.
|
||||
*/
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device),
|
||||
CONST_CAST(char*)json_area, hdr_json_len,
|
||||
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate checksum and write header with checkum.
|
||||
* Calculate checksum and write header with checksum.
|
||||
*/
|
||||
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
|
||||
json_area, hdr_json_len);
|
||||
if (r < 0) {
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
log_dbg_checksum(hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
|
||||
log_dbg_checksum(cd, hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
|
||||
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), (char *)&hdr_disk,
|
||||
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
|
||||
r = -EIO;
|
||||
|
||||
close(devfd);
|
||||
device_sync(cd, device);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_check_device_size(struct crypt_device *cd, struct device *device,
|
||||
uint64_t hdr_size, int falloc)
|
||||
static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
{
|
||||
uint64_t dev_size;
|
||||
int devfd;
|
||||
struct luks2_hdr_disk dhdr;
|
||||
|
||||
if (device_size(device, &dev_size)) {
|
||||
log_dbg("Cannot get device size for device %s.", device_path(device));
|
||||
if (!hdr)
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDONLY);
|
||||
if (devfd < 0)
|
||||
return devfd == -1 ? -EINVAL : devfd;
|
||||
|
||||
/* we need only first 512 bytes, see luks2_hdr_disk structure */
|
||||
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &dhdr, 512, 0) != 512))
|
||||
return -EIO;
|
||||
|
||||
/* there's nothing to check if there's no LUKS2 header */
|
||||
if ((be16_to_cpu(dhdr.version) != 2) ||
|
||||
memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) ||
|
||||
strcmp(dhdr.uuid, hdr->uuid))
|
||||
return 0;
|
||||
|
||||
return hdr->seqid != be64_to_cpu(dhdr.seqid);
|
||||
}
|
||||
|
||||
int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
{
|
||||
int r = device_write_lock(cd, device);
|
||||
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
log_dbg("Device size %" PRIu64 ", header size %"
|
||||
PRIu64 ".", dev_size, hdr_size);
|
||||
|
||||
if (hdr_size > dev_size) {
|
||||
/* If it is header file, increase its size */
|
||||
if (falloc && !device_fallocate(device, hdr_size))
|
||||
return 0;
|
||||
|
||||
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)\n"),
|
||||
device_path(device), hdr_size);
|
||||
return -EINVAL;
|
||||
/* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */
|
||||
if (r == 1 && !crypt_get_reenc_context(cd)) {
|
||||
log_dbg(cd, "Checking context sequence id matches value stored on disk.");
|
||||
if (LUKS2_check_sequence_id(cd, hdr, device)) {
|
||||
device_write_unlock(cd, device);
|
||||
log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation."));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -373,7 +401,7 @@ static int LUKS2_check_device_size(struct crypt_device *cd, struct device *devic
|
||||
* Convert in-memory LUKS2 header and write it to disk.
|
||||
* This will increase sequence id, write both header copies and calculate checksum.
|
||||
*/
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check)
|
||||
{
|
||||
char *json_area;
|
||||
const char *json_text;
|
||||
@@ -381,16 +409,11 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
int r;
|
||||
|
||||
if (hdr->version != 2) {
|
||||
log_dbg("Unsupported LUKS2 header version (%u).", hdr->version);
|
||||
log_dbg(cd, "Unsupported LUKS2 header version (%u).", hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr->hdr_size != LUKS2_HDR_16K_LEN) {
|
||||
log_dbg("Unsupported LUKS2 header size (%zu).", hdr->hdr_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_check_device_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1);
|
||||
r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -398,118 +421,128 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
* Allocate and zero JSON area (of proper header size).
|
||||
*/
|
||||
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
|
||||
json_area = malloc(json_area_len);
|
||||
json_area = crypt_zalloc(json_area_len);
|
||||
if (!json_area)
|
||||
return -ENOMEM;
|
||||
memset(json_area, 0, json_area_len);
|
||||
|
||||
/*
|
||||
* Generate text space-efficient JSON representation to json area.
|
||||
*/
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj, JSON_C_TO_STRING_PLAIN);
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
if (!json_text || !*json_text) {
|
||||
log_dbg("Cannot parse JSON object to text representation.");
|
||||
log_dbg(cd, "Cannot parse JSON object to text representation.");
|
||||
free(json_area);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (strlen(json_text) > (json_area_len - 1)) {
|
||||
log_dbg("JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
|
||||
log_dbg(cd, "JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
|
||||
free(json_area);
|
||||
return -EINVAL;
|
||||
}
|
||||
strncpy(json_area, json_text, json_area_len);
|
||||
|
||||
/* Increase sequence id before writing it to disk. */
|
||||
hdr->seqid++;
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write device lock.\n"));
|
||||
if (seqid_check)
|
||||
r = LUKS2_device_write_lock(cd, hdr, device);
|
||||
else
|
||||
r = device_write_lock(cd, device);
|
||||
if (r < 0) {
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Increase sequence id before writing it to disk. */
|
||||
hdr->seqid++;
|
||||
|
||||
/* Write primary and secondary header */
|
||||
r = hdr_write_disk(device, hdr, json_area, 0);
|
||||
r = hdr_write_disk(cd, device, hdr, json_area, 0);
|
||||
if (!r)
|
||||
r = hdr_write_disk(device, hdr, json_area, 1);
|
||||
r = hdr_write_disk(cd, device, hdr, json_area, 1);
|
||||
|
||||
if (r)
|
||||
log_dbg("LUKS2 header write failed (%d).", r);
|
||||
log_dbg(cd, "LUKS2 header write failed (%d).", r);
|
||||
|
||||
device_write_unlock(device);
|
||||
|
||||
/* FIXME: try recovery here? */
|
||||
device_write_unlock(cd, device);
|
||||
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int validate_json_area(const char *json_area, int start, int length)
|
||||
static int validate_json_area(struct crypt_device *cd, const char *json_area,
|
||||
uint64_t json_len, uint64_t max_length)
|
||||
{
|
||||
char c;
|
||||
|
||||
/* Enforce there are no needless opening bytes */
|
||||
if (*json_area != '{') {
|
||||
log_dbg("ERROR: Opening character must be left curly bracket: '{'.");
|
||||
log_dbg(cd, "ERROR: Opening character must be left curly bracket: '{'.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (start >= length) {
|
||||
log_dbg("ERROR: Missing trailing null byte beyond parsed json data string.");
|
||||
if (json_len >= max_length) {
|
||||
log_dbg(cd, "ERROR: Missing trailing null byte beyond parsed json data string.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* validate there are legal json format characters between
|
||||
* 'json_area' and 'json_area + start'
|
||||
* 'json_area' and 'json_area + json_len'
|
||||
*/
|
||||
|
||||
do {
|
||||
c = *(json_area + start);
|
||||
c = *(json_area + json_len);
|
||||
if (c != '\0') {
|
||||
log_dbg("ERROR: Forbidden ascii code 0x%02hhx found beyond json data string at offset %d.",
|
||||
c, start);
|
||||
log_dbg(cd, "ERROR: Forbidden ascii code 0x%02hhx found beyond json data string at offset %" PRIu64,
|
||||
c, json_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
} while (++start < length);
|
||||
} while (++json_len < max_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_luks2_json_object(json_object *jobj_hdr)
|
||||
static int validate_luks2_json_object(struct crypt_device *cd, json_object *jobj_hdr, uint64_t length)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* we require top level object to be of json_type_object */
|
||||
r = !json_object_is_type(jobj_hdr, json_type_object);
|
||||
if (r) {
|
||||
log_dbg("ERROR: Resulting object is not a json object type");
|
||||
log_dbg(cd, "ERROR: Resulting object is not a json object type");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_hdr_validate(jobj_hdr);
|
||||
r = LUKS2_hdr_validate(cd, jobj_hdr, length);
|
||||
if (r) {
|
||||
log_dbg(cd, "Repairing JSON metadata.");
|
||||
/* try to correct known glitches */
|
||||
LUKS2_hdr_repair(cd, jobj_hdr);
|
||||
|
||||
/* run validation again */
|
||||
r = LUKS2_hdr_validate(cd, jobj_hdr, length);
|
||||
}
|
||||
|
||||
if (r)
|
||||
log_dbg("ERROR: LUKS2 validation failed");
|
||||
log_dbg(cd, "ERROR: LUKS2 validation failed");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static json_object *parse_and_validate_json(const char *json_area, int length)
|
||||
static json_object *parse_and_validate_json(struct crypt_device *cd,
|
||||
const char *json_area, uint64_t max_length)
|
||||
{
|
||||
int offset, r;
|
||||
json_object *jobj = parse_json_len(json_area, length, &offset);
|
||||
int json_len, r;
|
||||
json_object *jobj = parse_json_len(cd, json_area, max_length, &json_len);
|
||||
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
/* successfull parse_json_len must not return offset <= 0 */
|
||||
assert(offset > 0);
|
||||
/* successful parse_json_len must not return offset <= 0 */
|
||||
assert(json_len > 0);
|
||||
|
||||
r = validate_json_area(json_area, offset, length);
|
||||
r = validate_json_area(cd, json_area, json_len, max_length);
|
||||
if (!r)
|
||||
r = validate_luks2_json_object(jobj);
|
||||
r = validate_luks2_json_object(cd, jobj, max_length);
|
||||
|
||||
if (r) {
|
||||
json_object_put(jobj);
|
||||
@@ -519,32 +552,82 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static int detect_device_signatures(struct crypt_device *cd, const char *path)
|
||||
{
|
||||
blk_probe_status prb_state;
|
||||
int r;
|
||||
struct blkid_handle *h;
|
||||
|
||||
if (!blk_supported()) {
|
||||
log_dbg(cd, "Blkid probing of device signatures disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = blk_init_by_path(&h, path))) {
|
||||
log_dbg(cd, "Failed to initialize blkid_handle by path.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We don't care about details. Be fast. */
|
||||
blk_set_chains_for_fast_detection(h);
|
||||
|
||||
/* Filter out crypto_LUKS. we don't care now */
|
||||
blk_superblocks_filter_luks(h);
|
||||
|
||||
prb_state = blk_safeprobe(h);
|
||||
|
||||
switch (prb_state) {
|
||||
case PRB_AMBIGUOUS:
|
||||
log_dbg(cd, "Blkid probe couldn't decide device type unambiguously.");
|
||||
/* fall through */
|
||||
case PRB_FAIL:
|
||||
log_dbg(cd, "Blkid probe failed.");
|
||||
r = -EINVAL;
|
||||
break;
|
||||
case PRB_OK: /* crypto_LUKS type is filtered out */
|
||||
r = -EINVAL;
|
||||
|
||||
if (blk_is_partition(h))
|
||||
log_dbg(cd, "Blkid probe detected partition type '%s'", blk_get_partition_type(h));
|
||||
else if (blk_is_superblock(h))
|
||||
log_dbg(cd, "blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
|
||||
break;
|
||||
case PRB_EMPTY:
|
||||
log_dbg(cd, "Blkid probe detected no foreign device signature.");
|
||||
}
|
||||
blk_free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and convert on-disk LUKS2 header to in-memory representation..
|
||||
* Try to do recovery if on-disk state is not consistent.
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery)
|
||||
struct device *device, int do_recovery, int do_blkprobe)
|
||||
{
|
||||
enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2;
|
||||
struct luks2_hdr_disk hdr_disk1, hdr_disk2;
|
||||
char *json_area1 = NULL, *json_area2 = NULL;
|
||||
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
|
||||
int i, r;
|
||||
unsigned int i;
|
||||
int r;
|
||||
uint64_t hdr_size;
|
||||
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
|
||||
|
||||
if (do_recovery && !crypt_metadata_locking_enabled()) {
|
||||
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
|
||||
if (do_recovery && do_blkprobe && !crypt_metadata_locking_enabled()) {
|
||||
do_recovery = 0;
|
||||
log_dbg("Disabling header auto-recovery due to locking being disabled.");
|
||||
log_dbg(cd, "Disabling header auto-recovery due to locking being disabled.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Read primary LUKS2 header (offset 0).
|
||||
*/
|
||||
state_hdr1 = HDR_FAIL;
|
||||
r = hdr_read_disk(device, &hdr_disk1, &json_area1, 0, 0);
|
||||
r = hdr_read_disk(cd, device, &hdr_disk1, &json_area1, 0, 0);
|
||||
if (r == 0) {
|
||||
jobj_hdr1 = parse_and_validate_json(json_area1, be64_to_cpu(hdr_disk1.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
state_hdr1 = jobj_hdr1 ? HDR_OK : HDR_OBSOLETE;
|
||||
} else if (r == -EIO)
|
||||
state_hdr1 = HDR_FAIL_IO;
|
||||
@@ -554,9 +637,9 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
*/
|
||||
state_hdr2 = HDR_FAIL;
|
||||
if (state_hdr1 != HDR_FAIL && state_hdr1 != HDR_FAIL_IO) {
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
|
||||
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
|
||||
if (r == 0) {
|
||||
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
|
||||
} else if (r == -EIO)
|
||||
state_hdr2 = HDR_FAIL_IO;
|
||||
@@ -564,11 +647,11 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/*
|
||||
* No header size, check all known offsets.
|
||||
*/
|
||||
for (r = -EINVAL,i = 2; r < 0 && i <= 1024; i <<= 1)
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, i * 4096, 1);
|
||||
for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++)
|
||||
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
|
||||
|
||||
if (r == 0) {
|
||||
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
|
||||
} else if (r == -EIO)
|
||||
state_hdr2 = HDR_FAIL_IO;
|
||||
@@ -594,7 +677,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = LUKS2_check_device_size(cd, device, hdr_size, 0);
|
||||
r = device_check_size(cd, device, hdr_size, 0);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
@@ -602,34 +685,46 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
* Try to rewrite (recover) bad header. Always regenerate salt for bad header.
|
||||
*/
|
||||
if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) {
|
||||
log_dbg("Secondary LUKS2 header requires recovery.");
|
||||
log_dbg(cd, "Secondary LUKS2 header requires recovery.");
|
||||
|
||||
if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) {
|
||||
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
|
||||
"Please run \"cryptsetup repair\" for recovery."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
|
||||
r = crypt_random_get(cd, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
|
||||
if (r)
|
||||
log_dbg("Cannot generate master salt.");
|
||||
log_dbg(cd, "Cannot generate master salt.");
|
||||
else {
|
||||
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
|
||||
r = hdr_write_disk(device, hdr, json_area1, 1);
|
||||
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
|
||||
}
|
||||
if (r)
|
||||
log_dbg("Secondary LUKS2 header recovery failed.");
|
||||
log_dbg(cd, "Secondary LUKS2 header recovery failed.");
|
||||
}
|
||||
} else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) {
|
||||
log_dbg("Primary LUKS2 header requires recovery.");
|
||||
log_dbg(cd, "Primary LUKS2 header requires recovery.");
|
||||
|
||||
if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) {
|
||||
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
|
||||
"Please run \"cryptsetup repair\" for recovery."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
|
||||
r = crypt_random_get(cd, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
|
||||
if (r)
|
||||
log_dbg("Cannot generate master salt.");
|
||||
log_dbg(cd, "Cannot generate master salt.");
|
||||
else {
|
||||
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
|
||||
r = hdr_write_disk(device, hdr, json_area2, 0);
|
||||
r = hdr_write_disk(cd, device, hdr, json_area2, 0);
|
||||
}
|
||||
if (r)
|
||||
log_dbg("Primary LUKS2 header recovery failed.");
|
||||
log_dbg(cd, "Primary LUKS2 header recovery failed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +756,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
*/
|
||||
return 0;
|
||||
err:
|
||||
log_dbg("LUKS2 header read failed (%d).", r);
|
||||
log_dbg(cd, "LUKS2 header read failed (%d).", r);
|
||||
|
||||
free(json_area1);
|
||||
free(json_area2);
|
||||
@@ -682,7 +777,7 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
|
||||
|
||||
if (!backup_file)
|
||||
device = crypt_metadata_device(cd);
|
||||
else if (device_alloc(&device, backup_file) < 0)
|
||||
else if (device_alloc(cd, &device, backup_file) < 0)
|
||||
return 0;
|
||||
|
||||
if (!device)
|
||||
@@ -696,7 +791,7 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
|
||||
if (devfd < 0)
|
||||
goto err;
|
||||
|
||||
if ((read_lseek_blockwise(devfd, device_block_size(device),
|
||||
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &hdr, sizeof(hdr), 0) == sizeof(hdr)) &&
|
||||
!memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
|
||||
r = (int)be16_to_cpu(hdr.version);
|
||||
@@ -705,7 +800,7 @@ err:
|
||||
close(devfd);
|
||||
|
||||
if (backup_file)
|
||||
device_free(device);
|
||||
device_free(cd, device);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -23,7 +23,6 @@
|
||||
#define _CRYPTSETUP_LUKS2_INTERNAL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
@@ -33,41 +32,63 @@
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* override useless forward slash escape when supported by json-c */
|
||||
#ifndef JSON_C_TO_STRING_NOSLASHESCAPE
|
||||
#define JSON_C_TO_STRING_NOSLASHESCAPE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On-disk access function prototypes
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery);
|
||||
struct device *device, int do_recovery, int do_blkprobe);
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device);
|
||||
struct device *device, bool seqid_check);
|
||||
|
||||
/*
|
||||
* JSON struct access helpers
|
||||
*/
|
||||
json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
|
||||
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
|
||||
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
|
||||
json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr);
|
||||
|
||||
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
const char *sep, const char *line_sep);
|
||||
|
||||
json_object *parse_json_len(const char *json_area, int length, int *end_offset);
|
||||
uint64_t json_object_get_uint64(json_object *jobj);
|
||||
uint32_t json_object_get_uint32(json_object *jobj);
|
||||
uint64_t crypt_jobj_get_uint64(json_object *jobj);
|
||||
uint32_t crypt_jobj_get_uint32(json_object *jobj);
|
||||
json_object *crypt_jobj_new_uint64(uint64_t value);
|
||||
|
||||
void JSON_DBG(json_object *jobj, const char *desc);
|
||||
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
|
||||
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
|
||||
int json_object_copy(json_object *jobj_src, json_object **jobj_dst);
|
||||
|
||||
void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
|
||||
|
||||
/*
|
||||
* LUKS2 JSON validation
|
||||
*/
|
||||
|
||||
int LUKS2_hdr_validate(json_object *hdr_jobj);
|
||||
int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, const char *key);
|
||||
int LUKS2_check_json_size(const struct luks2_hdr *hdr);
|
||||
int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const char *key);
|
||||
/* validation helper */
|
||||
json_bool validate_json_uint32(json_object *jobj);
|
||||
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
|
||||
const char *section, const char *key, json_type type);
|
||||
|
||||
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
|
||||
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);
|
||||
int LUKS2_token_validate(struct crypt_device *cd, json_object *hdr_jobj,
|
||||
json_object *jobj_token, const char *key);
|
||||
void LUKS2_token_dump(struct crypt_device *cd, int token);
|
||||
|
||||
/*
|
||||
* LUKS2 JSON repair for known glitches
|
||||
*/
|
||||
void LUKS2_hdr_repair(struct crypt_device *cd, json_object *jobj_hdr);
|
||||
void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_hdr);
|
||||
|
||||
/*
|
||||
* JSON array helpers
|
||||
*/
|
||||
@@ -82,7 +103,10 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
|
||||
* LUKS2 keyslots handlers (EXPERIMENTAL)
|
||||
*/
|
||||
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
|
||||
size_t volume_key_len);
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_update_func)(struct crypt_device *cd, int keyslot,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_open_func) (struct crypt_device *cd, int keyslot,
|
||||
const char *password, size_t password_len,
|
||||
char *volume_key, size_t volume_key_len);
|
||||
@@ -91,22 +115,37 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
|
||||
const char *volume_key, size_t volume_key_len);
|
||||
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
/* see LUKS2_luks2_to_luks1 */
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len);
|
||||
|
||||
/* validate all keyslot implementations in hdr json */
|
||||
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
keyslot_alloc_func alloc;
|
||||
keyslot_update_func update;
|
||||
keyslot_open_func open;
|
||||
keyslot_store_func store;
|
||||
keyslot_wipe_func wipe;
|
||||
keyslot_dump_func dump;
|
||||
keyslot_validate_func validate;
|
||||
keyslot_repair_func repair;
|
||||
} keyslot_handler;
|
||||
|
||||
/* can not fit prototype alloc function */
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* LUKS2 digest handlers (EXPERIMENTAL)
|
||||
*/
|
||||
@@ -123,13 +162,6 @@ typedef struct {
|
||||
digest_dump_func dump;
|
||||
} digest_handler;
|
||||
|
||||
int crypt_digest_register(const digest_handler *handler);
|
||||
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
int crypt_keyslot_assign_digest(struct crypt_device *cd, int keyslot, int digest);
|
||||
int crypt_keyslot_unassign_digest(struct crypt_device *cd, int keyslot, int digest);
|
||||
|
||||
/**
|
||||
* LUKS2 token handlers (internal use only)
|
||||
*/
|
||||
@@ -147,8 +179,25 @@ typedef struct {
|
||||
int token_keyring_set(json_object **, const void *);
|
||||
int token_keyring_get(json_object *, void *);
|
||||
|
||||
#define CRYPT_ANY_TOKEN -1
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
|
||||
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t *area_offset, uint64_t *area_length);
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
|
||||
static inline const char *crypt_reencrypt_mode_to_str(crypt_reencrypt_mode_info mi)
|
||||
{
|
||||
if (mi == CRYPT_REENCRYPT_REENCRYPT)
|
||||
return "reencrypt";
|
||||
if (mi == CRYPT_REENCRYPT_ENCRYPT)
|
||||
return "encrypt";
|
||||
if (mi == CRYPT_REENCRYPT_DECRYPT)
|
||||
return "decrypt";
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "luks2_internal.h"
|
||||
#include <uuid/uuid.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct area {
|
||||
uint64_t offset;
|
||||
@@ -38,9 +39,83 @@ static size_t get_min_offset(struct luks2_hdr *hdr)
|
||||
return 2 * hdr->hdr_size;
|
||||
}
|
||||
|
||||
static size_t get_max_offset(struct crypt_device *cd)
|
||||
static size_t get_max_offset(struct luks2_hdr *hdr)
|
||||
{
|
||||
return crypt_get_data_offset(cd) * SECTOR_SIZE;
|
||||
return LUKS2_hdr_and_areas_size(hdr->jobj);
|
||||
}
|
||||
|
||||
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t *area_offset, uint64_t *area_length)
|
||||
{
|
||||
struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX+1] = {};
|
||||
int i, j, k, area_i;
|
||||
size_t valid_offset, offset, length;
|
||||
|
||||
/* fill area offset + length table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length))
|
||||
continue;
|
||||
areas[i].length = 0;
|
||||
areas[i].offset = 0;
|
||||
}
|
||||
|
||||
/* sort table */
|
||||
k = 0; /* index in sorted table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
offset = get_max_offset(hdr) ?: UINT64_MAX;
|
||||
area_i = -1;
|
||||
/* search for the smallest offset in table */
|
||||
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
|
||||
if (areas[j].offset && areas[j].offset <= offset) {
|
||||
area_i = j;
|
||||
offset = areas[j].offset;
|
||||
}
|
||||
|
||||
if (area_i >= 0) {
|
||||
sorted_areas[k].length = areas[area_i].length;
|
||||
sorted_areas[k].offset = areas[area_i].offset;
|
||||
areas[area_i].length = 0;
|
||||
areas[area_i].offset = 0;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
sorted_areas[LUKS2_KEYSLOTS_MAX].offset = get_max_offset(hdr);
|
||||
sorted_areas[LUKS2_KEYSLOTS_MAX].length = 1;
|
||||
|
||||
/* search for the gap we can use */
|
||||
length = valid_offset = 0;
|
||||
offset = get_min_offset(hdr);
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX+1; i++) {
|
||||
/* skip empty */
|
||||
if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0)
|
||||
continue;
|
||||
|
||||
/* found bigger gap than the last one */
|
||||
if ((offset < sorted_areas[i].offset) && (sorted_areas[i].offset - offset) > length) {
|
||||
length = sorted_areas[i].offset - offset;
|
||||
valid_offset = offset;
|
||||
}
|
||||
|
||||
/* move beyond allocated area */
|
||||
offset = sorted_areas[i].offset + sorted_areas[i].length;
|
||||
}
|
||||
|
||||
/* this search 'algorithm' does not work with unaligned areas */
|
||||
assert(length == size_round_up(length, 4096));
|
||||
assert(valid_offset == size_round_up(valid_offset, 4096));
|
||||
|
||||
if (!length) {
|
||||
log_dbg(cd, "Not enough space in header keyslot area.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Found largest free area %zu -> %zu", valid_offset, length + valid_offset);
|
||||
|
||||
*area_offset = valid_offset;
|
||||
*area_length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
@@ -61,7 +136,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/* sort table */
|
||||
k = 0; /* index in sorted table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
offset = get_max_offset(cd) ?: UINT64_MAX;
|
||||
offset = get_max_offset(hdr) ?: UINT64_MAX;
|
||||
area_i = -1;
|
||||
/* search for the smallest offset in table */
|
||||
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
|
||||
@@ -95,25 +170,34 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
offset = sorted_areas[i].offset + sorted_areas[i].length;
|
||||
}
|
||||
|
||||
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
|
||||
log_err(cd, _("No space for new keyslot.\n"));
|
||||
if ((offset + length) > get_max_offset(hdr)) {
|
||||
log_dbg(cd, "Not enough space in header keyslot area.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg("Found area %zu -> %zu", offset, length + offset);
|
||||
/*
|
||||
log_dbg("Area offset min: %zu, max %zu, slots max %u",
|
||||
get_min_offset(hdr), get_max_offset(cd), LUKS2_KEYSLOTS_MAX);
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
|
||||
log_dbg("SLOT[%02i]: %-8" PRIu64 " -> %-8" PRIu64, i,
|
||||
sorted_areas[i].offset,
|
||||
sorted_areas[i].length + sorted_areas[i].offset);
|
||||
*/
|
||||
log_dbg(cd, "Found area %zu -> %zu", offset, length + offset);
|
||||
|
||||
*area_offset = offset;
|
||||
*area_length = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_check_metadata_area_size(uint64_t metadata_size)
|
||||
{
|
||||
/* see LUKS2_HDR2_OFFSETS */
|
||||
return (metadata_size != 0x004000 &&
|
||||
metadata_size != 0x008000 && metadata_size != 0x010000 &&
|
||||
metadata_size != 0x020000 && metadata_size != 0x040000 &&
|
||||
metadata_size != 0x080000 && metadata_size != 0x100000 &&
|
||||
metadata_size != 0x200000 && metadata_size != 0x400000);
|
||||
}
|
||||
|
||||
int LUKS2_check_keyslots_area_size(uint64_t keyslots_size)
|
||||
{
|
||||
return (MISALIGNED_4K(keyslots_size) ||
|
||||
keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE);
|
||||
}
|
||||
|
||||
int LUKS2_generate_hdr(
|
||||
struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
@@ -122,27 +206,81 @@ int LUKS2_generate_hdr(
|
||||
const char *cipherMode,
|
||||
const char *integrity,
|
||||
const char *uuid,
|
||||
unsigned int sector_size,
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
int detached_metadata_device)
|
||||
unsigned int sector_size, /* in bytes */
|
||||
uint64_t data_offset, /* in bytes */
|
||||
uint64_t align_offset, /* in bytes */
|
||||
uint64_t required_alignment,
|
||||
uint64_t metadata_size,
|
||||
uint64_t keyslots_size)
|
||||
{
|
||||
struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
|
||||
char num[24], cipher[128];
|
||||
uint64_t offset, json_size, keyslots_size;
|
||||
char cipher[128];
|
||||
uuid_t partitionUuid;
|
||||
int digest;
|
||||
uint64_t mdev_size;
|
||||
|
||||
if (!metadata_size)
|
||||
metadata_size = LUKS2_HDR_16K_LEN;
|
||||
hdr->hdr_size = metadata_size;
|
||||
|
||||
if (data_offset && data_offset < get_min_offset(hdr)) {
|
||||
log_err(cd, _("Requested data offset is too small."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Increase keyslot size according to data offset */
|
||||
if (!keyslots_size && data_offset)
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
|
||||
|
||||
if (!keyslots_size) {
|
||||
assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
|
||||
keyslots_size = LUKS2_DEFAULT_HDR_SIZE - get_min_offset(hdr);
|
||||
/* Decrease keyslots_size due to metadata device being too small */
|
||||
if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
|
||||
((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
|
||||
device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)))
|
||||
keyslots_size = mdev_size - get_min_offset(hdr);
|
||||
}
|
||||
|
||||
/* Decrease keyslots_size if we have smaller data_offset */
|
||||
if (data_offset && (keyslots_size + get_min_offset(hdr)) > data_offset) {
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
|
||||
" bytes due to the requested data offset %"
|
||||
PRIu64 " bytes.", keyslots_size, data_offset);
|
||||
}
|
||||
|
||||
/* Data offset has priority */
|
||||
if (!data_offset && required_alignment) {
|
||||
data_offset = size_round_up(get_min_offset(hdr) + keyslots_size,
|
||||
(size_t)required_alignment);
|
||||
data_offset += align_offset;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Formatting LUKS2 with JSON metadata area %" PRIu64
|
||||
" bytes and keyslots area %" PRIu64 " bytes.",
|
||||
metadata_size - LUKS2_HDR_BIN_LEN, keyslots_size);
|
||||
|
||||
if (keyslots_size < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
|
||||
log_std(cd, _("WARNING: keyslots area (%" PRIu64 " bytes) is very small,"
|
||||
" available LUKS2 keyslot count is very limited.\n"),
|
||||
keyslots_size);
|
||||
|
||||
hdr->hdr_size = LUKS2_HDR_16K_LEN;
|
||||
hdr->seqid = 1;
|
||||
hdr->version = 2;
|
||||
memset(hdr->label, 0, LUKS2_LABEL_L);
|
||||
strcpy(hdr->checksum_alg, "sha256");
|
||||
crypt_random_get(NULL, (char*)hdr->salt1, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
crypt_random_get(NULL, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
crypt_random_get(cd, (char*)hdr->salt1, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
crypt_random_get(cd, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(cd, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -167,34 +305,15 @@ int LUKS2_generate_hdr(
|
||||
json_object_object_add(hdr->jobj, "config", jobj_config);
|
||||
|
||||
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
|
||||
if (digest < 0) {
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (digest < 0)
|
||||
goto err;
|
||||
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, CRYPT_DEFAULT_SEGMENT, digest, 1, 0) < 0) {
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
|
||||
goto err;
|
||||
|
||||
jobj_segment = json_object_new_object();
|
||||
json_object_object_add(jobj_segment, "type", json_object_new_string("crypt"));
|
||||
if (detached_metadata_device)
|
||||
offset = (uint64_t)alignPayload * sector_size;
|
||||
else {
|
||||
//FIXME
|
||||
//offset = size_round_up(areas[7].offset + areas[7].length, alignPayload * SECTOR_SIZE);
|
||||
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, alignPayload * sector_size);
|
||||
offset += alignOffset;
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_segment, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
|
||||
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
|
||||
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));
|
||||
jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
|
||||
if (!jobj_segment)
|
||||
goto err;
|
||||
|
||||
if (integrity) {
|
||||
jobj_integrity = json_object_new_object();
|
||||
@@ -204,19 +323,72 @@ int LUKS2_generate_hdr(
|
||||
json_object_object_add(jobj_segment, "integrity", jobj_integrity);
|
||||
}
|
||||
|
||||
snprintf(num, sizeof(num), "%u", CRYPT_DEFAULT_SEGMENT);
|
||||
json_object_object_add(jobj_segments, num, jobj_segment);
|
||||
json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
|
||||
|
||||
json_size = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
|
||||
json_object_object_add(jobj_config, "json_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
|
||||
json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
|
||||
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
|
||||
|
||||
/* for detached metadata device compute reasonable keyslot areas size */
|
||||
// FIXME: this is coupled with FIXME above
|
||||
if (detached_metadata_device)
|
||||
keyslots_size = LUKS2_HDR_DEFAULT_LEN - get_min_offset(hdr);
|
||||
else
|
||||
keyslots_size = offset - get_min_offset(hdr);
|
||||
JSON_DBG(cd, hdr->jobj, "Header JSON:");
|
||||
return 0;
|
||||
err:
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr)
|
||||
{
|
||||
int r;
|
||||
uint64_t offset, length;
|
||||
size_t wipe_block;
|
||||
|
||||
/* Wipe complete header, keyslots and padding areas with zeroes. */
|
||||
offset = 0;
|
||||
length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE;
|
||||
wipe_block = 1024 * 1024;
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
/* On detached header wipe at least the first 4k */
|
||||
if (length == 0) {
|
||||
length = 4096;
|
||||
wipe_block = 4096;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
|
||||
offset, length + offset);
|
||||
|
||||
r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Wipe keyslot area */
|
||||
wipe_block = 1024 * 1024;
|
||||
offset = get_min_offset(hdr);
|
||||
length = LUKS2_keyslots_size(hdr->jobj);
|
||||
|
||||
log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
|
||||
offset, length + offset);
|
||||
|
||||
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
}
|
||||
|
||||
/* FIXME: what if user wanted to keep original keyslots size? */
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset)
|
||||
{
|
||||
json_object *jobj_config;
|
||||
uint64_t keyslots_size;
|
||||
|
||||
if (data_offset < get_min_offset(hdr))
|
||||
return 1;
|
||||
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
|
||||
/* keep keyslots_size reasonable for custom data alignments */
|
||||
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
@@ -225,9 +397,9 @@ int LUKS2_generate_hdr(
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
json_object_object_add(jobj_config, "keyslots_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
|
||||
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
|
||||
return 1;
|
||||
|
||||
JSON_DBG(hdr->jobj, "Header JSON");
|
||||
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, keyslot handling
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -23,9 +23,11 @@
|
||||
|
||||
/* Internal implementations */
|
||||
extern const keyslot_handler luks2_keyslot;
|
||||
extern const keyslot_handler reenc_keyslot;
|
||||
|
||||
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
|
||||
&luks2_keyslot,
|
||||
&reenc_keyslot,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -63,15 +65,7 @@ static const keyslot_handler
|
||||
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
|
||||
}
|
||||
|
||||
static crypt_keyslot_info LUKS2_keyslot_active(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
if (keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
return LUKS2_get_keyslot_jobj(hdr, keyslot) ? CRYPT_SLOT_ACTIVE : CRYPT_SLOT_INACTIVE;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -82,77 +76,58 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int digests_by_segment(json_object *jobj_digests, const char *segment,
|
||||
digests_t digests)
|
||||
/* Check if a keyslot is assigned to specific segment */
|
||||
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
json_object *jobj_segs;
|
||||
int i = 0;
|
||||
int keyslot_digest, count = 0;
|
||||
unsigned s;
|
||||
|
||||
json_object_object_foreach(jobj_digests, dig, val) {
|
||||
json_object_object_get_ex(val, "segments", &jobj_segs);
|
||||
if (LUKS2_array_jobj(jobj_segs, segment))
|
||||
digests[i++] = atoi(dig);
|
||||
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (keyslot_digest < 0)
|
||||
return keyslot_digest;
|
||||
|
||||
if (segment >= 0)
|
||||
return keyslot_digest == LUKS2_digest_by_segment(hdr, segment);
|
||||
|
||||
for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
|
||||
if (keyslot_digest == LUKS2_digest_by_segment(hdr, s))
|
||||
count++;
|
||||
}
|
||||
|
||||
if (i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int is_in(const int super[], int super_size, int elem)
|
||||
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
|
||||
{
|
||||
int i;
|
||||
int r = -EINVAL;
|
||||
|
||||
for (i = 0; i < super_size && super[i] != -1; i++)
|
||||
if (super[i] == elem)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_subset(const int super[], const int sub[], int super_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < super_size && sub[i] != -1; i++)
|
||||
if (!is_in(super, super_size, sub[i]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
r = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r == digest ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
char keyslot_name[16], segment_name[16];
|
||||
digests_t keyslot_digests, segment_digests;
|
||||
json_object *jobj_digests;
|
||||
int r = -ENOENT;
|
||||
int r = -EINVAL;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0;
|
||||
return 0; /* ok */
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT) {
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
if (segment < 0)
|
||||
return segment;
|
||||
}
|
||||
|
||||
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1 ||
|
||||
snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* empty set is subset of any set and it'd be wrong */
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
r = LUKS2_digests_by_keyslot(NULL, hdr, keyslot, keyslot_digests);
|
||||
if (r)
|
||||
r = _keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* empty set can't be superset of non-empty one */
|
||||
if (digests_by_segment(jobj_digests, segment_name, segment_digests))
|
||||
return r;
|
||||
|
||||
/*
|
||||
* keyslot may activate segment if set of digests for keyslot
|
||||
* is actually subset of set of digests for segment
|
||||
*/
|
||||
return is_subset(segment_digests, keyslot_digests, LUKS2_DIGEST_MAX) ? 0 : -ENOENT;
|
||||
return r >= 1 ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
{
|
||||
int num = 0;
|
||||
@@ -160,7 +135,6 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
|
||||
|
||||
/* keyslot digests must be subset of segment digests */
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
UNUSED(val);
|
||||
if (!LUKS2_keyslot_for_segment(hdr, atoi(slot), segment))
|
||||
@@ -170,18 +144,138 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
return num;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec)
|
||||
{
|
||||
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
|
||||
if (!cipher_spec || !strcmp(cipher_spec, "null") || !strcmp(cipher_spec, "cipher_null"))
|
||||
return 1;
|
||||
|
||||
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
|
||||
return 1;
|
||||
|
||||
/* Keyslot is already authenticated; we cannot use integrity tags here */
|
||||
if (crypt_get_integrity_tag_size(cd))
|
||||
return 1;
|
||||
|
||||
/* Wrapped key schemes cannot be used for keyslot encryption */
|
||||
if (crypt_cipher_wrapped_key(cipher, cipher_mode))
|
||||
return 1;
|
||||
|
||||
/* Check if crypto backend can use the cipher */
|
||||
if (crypt_cipher_ivsize(cipher, cipher_mode) < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct luks2_keyslot_params *params)
|
||||
{
|
||||
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
|
||||
const char *cipher_spec;
|
||||
size_t key_size;
|
||||
int r;
|
||||
|
||||
if (!hdr || !pbkdf || !params)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* set keyslot area encryption parameters
|
||||
*/
|
||||
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
|
||||
cipher_spec = crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size);
|
||||
if (!cipher_spec || !key_size)
|
||||
return -EINVAL;
|
||||
|
||||
params->area.raw.key_size = key_size;
|
||||
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s", cipher_spec);
|
||||
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* set keyslot AF parameters
|
||||
*/
|
||||
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
|
||||
/* currently we use hash for AF from pbkdf settings */
|
||||
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash ?: DEFAULT_LUKS1_HASH);
|
||||
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
|
||||
return -EINVAL;
|
||||
params->af.luks1.stripes = 4000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_kdf, *jobj;
|
||||
|
||||
if (!hdr || !pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -ENOENT;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj))
|
||||
return -EINVAL;
|
||||
|
||||
memset(pbkdf, 0, sizeof(*pbkdf));
|
||||
|
||||
pbkdf->type = json_object_get_string(jobj);
|
||||
if (json_object_object_get_ex(jobj_kdf, "hash", &jobj))
|
||||
pbkdf->hash = json_object_get_string(jobj);
|
||||
if (json_object_object_get_ex(jobj_kdf, "iterations", &jobj))
|
||||
pbkdf->iterations = json_object_get_int(jobj);
|
||||
if (json_object_object_get_ex(jobj_kdf, "time", &jobj))
|
||||
pbkdf->iterations = json_object_get_int(jobj);
|
||||
if (json_object_object_get_ex(jobj_kdf, "memory", &jobj))
|
||||
pbkdf->max_memory_kb = json_object_get_int(jobj);
|
||||
if (json_object_object_get_ex(jobj_kdf, "cpus", &jobj))
|
||||
pbkdf->parallel_threads = json_object_get_int(jobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_unbound(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
json_object *jobj_digest, *jobj_segments;
|
||||
int digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
|
||||
if (digest < 0)
|
||||
return 0;
|
||||
|
||||
if (!(jobj_digest = LUKS2_get_digest_jobj(hdr, digest)))
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj_segments);
|
||||
if (!jobj_segments || !json_object_is_type(jobj_segments, json_type_array) ||
|
||||
json_object_array_length(jobj_segments) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
crypt_keyslot_info ki;
|
||||
|
||||
if(keyslot >= LUKS2_KEYSLOTS_MAX || keyslot < 0)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
ki = LUKS2_keyslot_active(hdr, keyslot);
|
||||
if (ki != CRYPT_SLOT_ACTIVE)
|
||||
return ki;
|
||||
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return CRYPT_SLOT_INACTIVE;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 && !LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
if (LUKS2_digest_by_keyslot(hdr, keyslot) < 0 ||
|
||||
LUKS2_keyslot_unbound(hdr, keyslot))
|
||||
return CRYPT_SLOT_UNBOUND;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
|
||||
!LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
return CRYPT_SLOT_ACTIVE_LAST;
|
||||
|
||||
return CRYPT_SLOT_ACTIVE;
|
||||
@@ -206,15 +300,78 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
|
||||
return -EINVAL;
|
||||
*offset = json_object_get_int64(jobj);
|
||||
*offset = crypt_jobj_get_uint64(jobj);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
|
||||
return -EINVAL;
|
||||
*length = json_object_get_int64(jobj);
|
||||
*length = crypt_jobj_get_uint64(jobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _open_and_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const keyslot_handler *h,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
|
||||
|
||||
if (key_size < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_size, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
|
||||
if (r < 0)
|
||||
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
|
||||
else
|
||||
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
|
||||
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
}
|
||||
|
||||
crypt_volume_key_set_id(*vk, r);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = _keyslot_for_digest(hdr, keyslot, digest);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
|
||||
return r;
|
||||
}
|
||||
|
||||
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -224,40 +381,63 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int key_size, r;
|
||||
int r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg("Keyslot %d unusable for segment %d.", keyslot, segment);
|
||||
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
|
||||
return r;
|
||||
}
|
||||
|
||||
key_size = LUKS2_get_volume_key_size(hdr, segment);
|
||||
if (key_size < 0)
|
||||
key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
|
||||
if (key_size < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_size, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
|
||||
if (r < 0)
|
||||
log_dbg("Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
|
||||
else
|
||||
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
|
||||
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Keyslot %d unusable for segment %d.", keyslot, segment);
|
||||
return r;
|
||||
}
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
crypt_keyslot_priority priority,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
int digest,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
json_object *jobj_keyslots, *jobj;
|
||||
crypt_keyslot_priority slot_priority;
|
||||
int keyslot, r = -ENOENT;
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
if (!json_object_object_get_ex(val, "priority", &jobj))
|
||||
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
|
||||
else
|
||||
slot_priority = json_object_get_int(jobj);
|
||||
|
||||
keyslot = atoi(slot);
|
||||
if (slot_priority != priority) {
|
||||
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
|
||||
keyslot, slot_priority, priority);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
/* Do not retry for errors that are no -EPERM or -ENOENT,
|
||||
former meaning password wrong, latter key slot unusable for segment */
|
||||
if ((r != -EPERM) && (r != -ENOENT))
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
@@ -282,7 +462,7 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
|
||||
keyslot = atoi(slot);
|
||||
if (slot_priority != priority) {
|
||||
log_dbg("Keyslot %d priority %d != %d (required), skipped.",
|
||||
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
|
||||
keyslot, slot_priority, priority);
|
||||
continue;
|
||||
}
|
||||
@@ -298,6 +478,79 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
int r_prio, r = -EINVAL;
|
||||
|
||||
if (digest < 0)
|
||||
return r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT) {
|
||||
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
|
||||
password, password_len, digest, vk);
|
||||
if (r_prio >= 0)
|
||||
r = r_prio;
|
||||
else if (r_prio != -EPERM && r_prio != -ENOENT)
|
||||
r = r_prio;
|
||||
else
|
||||
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
|
||||
password, password_len, digest, vk);
|
||||
/* Prefer password wrong to no entry from priority slot */
|
||||
if (r_prio == -EPERM && r == -ENOENT)
|
||||
r = r_prio;
|
||||
} else
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks)
|
||||
{
|
||||
struct volume_key *vk = NULL;
|
||||
int digest_old, digest_new, r = -EINVAL;
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
digest_old = LUKS2_reencrypt_digest_old(hdr);
|
||||
if (digest_old >= 0) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
|
||||
digest_new = LUKS2_reencrypt_digest_new(hdr);
|
||||
if (digest_new >= 0 && digest_old != digest_new) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
out:
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vks);
|
||||
*vks = NULL;
|
||||
|
||||
if (r == -ENOMEM)
|
||||
log_err(cd, _("Not enough available memory to open a keyslot."));
|
||||
else if (r != -EPERM)
|
||||
log_err(cd, _("Keyslot open failed."));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
int segment,
|
||||
@@ -315,7 +568,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
password, password_len, segment, vk);
|
||||
if (r_prio >= 0)
|
||||
r = r_prio;
|
||||
else if (r_prio < 0 && (r_prio != -EPERM) && (r_prio != -ENOENT))
|
||||
else if (r_prio != -EPERM && r_prio != -ENOENT)
|
||||
r = r_prio;
|
||||
else
|
||||
r = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
|
||||
@@ -326,15 +579,81 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
} else
|
||||
r = LUKS2_open_and_verify(cd, hdr, keyslot, segment, password, password_len, vk);
|
||||
|
||||
if (r < 0) {
|
||||
if (r == -ENOMEM)
|
||||
log_err(cd, _("Not enough available memory to open a keyslot."));
|
||||
else if (r != -EPERM)
|
||||
log_err(cd, _("Keyslot open failed."));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: find keyslot by type */
|
||||
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)) || strcmp(h->name, "reencrypt"))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
return h->store(cd, keyslot, NULL, 0,
|
||||
buffer, buffer_length);
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
const struct volume_key *vk)
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
@@ -348,18 +667,29 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->alloc(cd, keyslot, vk->keylength);
|
||||
r = h->alloc(cd, keyslot, vk->keylength, params);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, keyslot);
|
||||
r = h->update(cd, keyslot, params);
|
||||
if (r) {
|
||||
log_dbg(cd, "Failed to update keyslot %d json.", keyslot);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg("Keyslot validation failed.");
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return h->store(cd, keyslot, password, password_len,
|
||||
vk->key, vk->keylength);
|
||||
}
|
||||
@@ -371,7 +701,6 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
{
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
uint64_t area_offset, area_length;
|
||||
char num[16];
|
||||
int r;
|
||||
json_object *jobj_keyslot, *jobj_keyslots;
|
||||
const keyslot_handler *h;
|
||||
@@ -386,52 +715,48 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
return -ENOENT;
|
||||
|
||||
if (wipe_area_only)
|
||||
log_dbg("Wiping keyslot %d area only.", keyslot);
|
||||
log_dbg(cd, "Wiping keyslot %d area only.", keyslot);
|
||||
|
||||
/* Just check that nobody uses the metadata now */
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
device_path(device));
|
||||
r = LUKS2_device_write_lock(cd, hdr, device);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
device_write_unlock(device);
|
||||
|
||||
/* secure deletion of possible key material in keyslot area */
|
||||
r = crypt_keyslot_area(cd, keyslot, &area_offset, &area_length);
|
||||
if (r && r != -ENOENT)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
/* We can destroy the binary keyslot area now without lock */
|
||||
if (!r) {
|
||||
r = crypt_wipe_device(cd, device, CRYPT_WIPE_SPECIAL, area_offset,
|
||||
area_length, area_length, NULL, NULL);
|
||||
if (r) {
|
||||
if (r == -EACCES) {
|
||||
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(cd, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(cd, _("Cannot wipe device %s.\n"), device_path(device));
|
||||
return r;
|
||||
log_err(cd, _("Cannot wipe device %s."), device_path(device));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (wipe_area_only)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
/* Slot specific wipe */
|
||||
if (h) {
|
||||
r = h->wipe(cd, keyslot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto out;
|
||||
} else
|
||||
log_dbg("Wiping keyslot %d without specific-slot handler loaded.", keyslot);
|
||||
log_dbg(cd, "Wiping keyslot %d without specific-slot handler loaded.", keyslot);
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
|
||||
return LUKS2_hdr_write(cd, hdr);
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
out:
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
@@ -475,3 +800,138 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
|
||||
log_dbg(cd, "Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("placeholder"));
|
||||
/*
|
||||
* key_size = -1 makes placeholder keyslot impossible to pass validation.
|
||||
* It's a safeguard against accidentally storing temporary conversion
|
||||
* LUKS2 header.
|
||||
*/
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(-1));
|
||||
|
||||
/* Area object */
|
||||
jobj_area = json_object_new_object();
|
||||
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned LUKS2_get_keyslot_digests_count(json_object *hdr_jobj, int keyslot)
|
||||
{
|
||||
char num[16];
|
||||
json_object *jobj_digests, *jobj_keyslots;
|
||||
unsigned count = 0;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
|
||||
return 0;
|
||||
|
||||
if (snprintf(num, sizeof(num), "%u", keyslot) < 0)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
UNUSED(key);
|
||||
json_object_object_get_ex(val, "keyslots", &jobj_keyslots);
|
||||
if (LUKS2_array_jobj(jobj_keyslots, num))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* run only on header that passed basic format validation */
|
||||
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int keyslot;
|
||||
json_object *jobj_keyslots, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
keyslot = atoi(slot);
|
||||
json_object_object_get_ex(val, "type", &jobj_type);
|
||||
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
|
||||
if (!h)
|
||||
continue;
|
||||
if (h->validate && h->validate(cd, val)) {
|
||||
log_dbg(cd, "Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(h->name, "luks2") && LUKS2_get_keyslot_digests_count(hdr_jobj, keyslot) != 1) {
|
||||
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
json_object *jobj_type;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!json_object_is_type(val, json_type_object) ||
|
||||
!json_object_object_get_ex(val, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
continue;
|
||||
|
||||
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
|
||||
if (h && h->repair)
|
||||
h->repair(cd, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* assumes valid header */
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_keyslot, *jobj_type;
|
||||
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
|
||||
if (!jobj_keyslot)
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
|
||||
if (!strcmp(json_object_get_string(jobj_type), type))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -28,66 +28,54 @@
|
||||
#define LUKS_SLOT_ITERATIONS_MIN 1000
|
||||
#define LUKS_STRIPES 4000
|
||||
|
||||
/* Serialize memory-hard keyslot access: optional workaround for parallel processing */
|
||||
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
|
||||
|
||||
static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
struct volume_key *vk, unsigned int sector,
|
||||
struct crypt_device *cd)
|
||||
{
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
device_write_unlock(crypt_metadata_device(cd));
|
||||
return r;
|
||||
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
#else
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (srcLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
if (r) {
|
||||
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
|
||||
r = crypt_storage_encrypt(s, 0, srcLength, src);
|
||||
crypt_storage_destroy(s);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
device_path(device));
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
return r;
|
||||
}
|
||||
|
||||
devfd = device_open_locked(device, O_RDWR);
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
write_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src,
|
||||
srcLength) == -1)
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), src,
|
||||
srcLength, sector * SECTOR_SIZE) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
close(devfd);
|
||||
|
||||
device_sync(cd, device);
|
||||
} else
|
||||
r = -EIO;
|
||||
|
||||
device_write_unlock(device);
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
#endif
|
||||
@@ -101,60 +89,109 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_decrypt_from_storage(dst, dstLength, cipher, cipher_mode, vk, sector, cd);
|
||||
device_read_unlock(crypt_metadata_device(cd));
|
||||
device_read_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
#else
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (dstLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
if (r) {
|
||||
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(device));
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
devfd = device_open_locked(cd, device, O_RDONLY);
|
||||
if (devfd >= 0) {
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
read_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst, dstLength) == -1)
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), dst,
|
||||
dstLength, sector * SECTOR_SIZE) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
close(devfd);
|
||||
} else
|
||||
r = -EIO;
|
||||
|
||||
device_read_unlock(device);
|
||||
device_read_unlock(cd, device);
|
||||
|
||||
/* Decrypt buffer */
|
||||
if (!r)
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
r = crypt_storage_decrypt(s, 0, dstLength, dst);
|
||||
else
|
||||
log_err(cd, _("IO error while decrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while decrypting keyslot."));
|
||||
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
|
||||
struct crypt_pbkdf_type *pbkdf, char *salt)
|
||||
{
|
||||
json_object *jobj_kdf, *jobj1, *jobj2;
|
||||
size_t salt_len;
|
||||
|
||||
if (!jobj_keyslot || !pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
memset(pbkdf, 0, sizeof(*pbkdf));
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
pbkdf->type = json_object_get_string(jobj1);
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
pbkdf->max_memory_kb = 0;
|
||||
pbkdf->parallel_threads = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->max_memory_kb = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->parallel_threads = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const char *password, size_t passwordLen,
|
||||
@@ -162,11 +199,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *AfKey = NULL, *salt_base64 = NULL;
|
||||
char *AfKey = NULL;
|
||||
const char *af_hash = NULL;
|
||||
size_t AFEKSize, keyslot_key_len;
|
||||
json_object *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
@@ -174,9 +212,15 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
/* prevent accidental volume key size change after allocation */
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "key_size", &jobj2))
|
||||
return -EINVAL;
|
||||
if (json_object_get_int(jobj2) != (int)volume_key_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
|
||||
return -EINVAL;
|
||||
area_offset = json_object_get_uint64(jobj2);
|
||||
area_offset = crypt_jobj_get_uint64(jobj2);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "encryption", &jobj2))
|
||||
return -EINVAL;
|
||||
@@ -188,52 +232,27 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
keyslot_key_len = json_object_get_int(jobj2);
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
af_hash = json_object_get_string(jobj2);
|
||||
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
/*
|
||||
* Get salt and allocate derived key storage.
|
||||
* Allocate derived key storage.
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
|
||||
|
||||
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
|
||||
if (!derived_key)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Calculate keyslot content, split and store it to keyslot area.
|
||||
*/
|
||||
r = crypt_pbkdf(pbkdf->type, pbkdf->hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
pbkdf->iterations, pbkdf->max_memory_kb,
|
||||
pbkdf->parallel_threads);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(derived_key);
|
||||
return r;
|
||||
@@ -247,10 +266,10 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, pbkdf->hash);
|
||||
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Updating keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
log_dbg(cd, "Updating keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
|
||||
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
|
||||
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
|
||||
@@ -261,7 +280,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
JSON_DBG(jobj_keyslot, "Keyslot JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -271,53 +289,22 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
char *volume_key, size_t volume_key_len)
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
char *AfKey;
|
||||
size_t AFEKSize;
|
||||
const char *hash = NULL, *af_hash = NULL, *kdf;
|
||||
const char *af_hash = NULL;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
json_object *jobj1, *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint32_t iterations, memory, parallel;
|
||||
json_object *jobj2, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
size_t salt_len, keyslot_key_len;
|
||||
size_t keyslot_key_len;
|
||||
bool try_serialize_lock = false;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
kdf = json_object_get_string(jobj1);
|
||||
if (!strcmp(kdf, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
memory = 0;
|
||||
parallel = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
memory = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
parallel = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
@@ -326,7 +313,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
|
||||
return -EINVAL;
|
||||
area_offset = json_object_get_uint64(jobj2);
|
||||
area_offset = crypt_jobj_get_uint64(jobj2);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "encryption", &jobj2))
|
||||
return -EINVAL;
|
||||
@@ -338,6 +325,13 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
keyslot_key_len = json_object_get_int(jobj2);
|
||||
|
||||
/*
|
||||
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
|
||||
*/
|
||||
if (pbkdf.max_memory_kb > MIN_MEMORY_FOR_SERIALIZE_LOCK_KB)
|
||||
try_serialize_lock = true;
|
||||
if (try_serialize_lock && crypt_serialize_lock(cd))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Allocate derived key storage space.
|
||||
*/
|
||||
@@ -354,20 +348,24 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
/*
|
||||
* Calculate derived key, decrypt keyslot content and merge it.
|
||||
*/
|
||||
r = crypt_pbkdf(kdf, hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
iterations, memory, parallel);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
|
||||
if (try_serialize_lock)
|
||||
crypt_serialize_unlock(cd);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
|
||||
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
|
||||
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
r = AF_merge(AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
r = AF_merge(cd, AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
|
||||
crypt_free_volume_key(derived_key);
|
||||
crypt_safe_free(AfKey);
|
||||
@@ -375,32 +373,102 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
size_t volume_key_len)
|
||||
/*
|
||||
* currently we support update of only:
|
||||
*
|
||||
* - af hash function
|
||||
* - kdf params
|
||||
*/
|
||||
static int luks2_keyslot_update_json(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
char area_offset_string[24], area_length_string[24];
|
||||
char cipher[2 * MAX_CIPHER_LEN + 1], num[16];
|
||||
uint64_t area_offset, area_length;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
size_t keyslot_key_len;
|
||||
json_object *jobj_af, *jobj_area, *jobj_kdf;
|
||||
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
|
||||
int r;
|
||||
|
||||
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
|
||||
/* jobj_keyslot is not yet validated */
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
/* update area encryption parameters */
|
||||
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, params->area.raw.key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* refresh whole 'kdf' object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
if (!jobj_kdf)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/*
|
||||
* Regenerate salt and add it in 'kdf' object
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
/* update 'af' hash */
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
|
||||
|
||||
JSON_DBG(cd, jobj_keyslot, "Keyslot JSON:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
uint64_t area_offset, area_length;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
|
||||
int r;
|
||||
|
||||
log_dbg(cd, "Trying to allocate LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!params || params->area_type != LUKS2_KEYSLOT_AREA_RAW ||
|
||||
params->af_type != LUKS2_KEYSLOT_AF_LUKS1) {
|
||||
log_dbg(cd, "Invalid LUKS2 keyslot parameters.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr);
|
||||
|
||||
if (keyslot < 0 || keyslot > LUKS2_KEYSLOTS_MAX)
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot)) {
|
||||
log_dbg("Cannot modify already active keyslot %d.", keyslot);
|
||||
log_dbg(cd, "Cannot modify already active keyslot %d.", keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -408,77 +476,41 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_find_area_gap(cd, hdr, volume_key_len, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_err(cd, _("No space for new keyslot."));
|
||||
return r;
|
||||
}
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(volume_key_len));
|
||||
|
||||
/* PBKDF object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/* AF object */
|
||||
jobj_af = json_object_new_object();
|
||||
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
|
||||
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
|
||||
json_object_object_add(jobj_keyslot, "af", jobj_af);
|
||||
|
||||
/* Area object */
|
||||
jobj_area = json_object_new_object();
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
|
||||
|
||||
/* Slot encryption tries to use the same key size as fot the main algorithm */
|
||||
keyslot_key_len = volume_key_len - crypt_get_integrity_key_size(cd);
|
||||
|
||||
/* Cannot use metadata tags in keyslot */
|
||||
if (crypt_get_integrity_tag_size(cd)) {
|
||||
snprintf(cipher, sizeof(cipher), "aes-xts-plain64"); // FIXME: fixed cipher and key size can be wrong
|
||||
keyslot_key_len = 32;
|
||||
} else if (crypt_get_cipher_mode(cd))
|
||||
snprintf(cipher, sizeof(cipher), "%s-%s", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
|
||||
else
|
||||
snprintf(cipher, sizeof(cipher), "%s", crypt_get_cipher(cd));
|
||||
|
||||
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(keyslot_key_len));
|
||||
uint64_to_str(area_offset_string, sizeof(area_offset_string), &area_offset);
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(area_offset_string));
|
||||
uint64_to_str(area_length_string, sizeof(area_length_string), &area_length);
|
||||
json_object_object_add(jobj_area, "size", json_object_new_string(area_length_string));
|
||||
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
|
||||
|
||||
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for new keyslot.");
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
return -ENOSPC;
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "Not enough space in header json area for new keyslot.");
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (r)
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
@@ -491,7 +523,7 @@ static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
|
||||
log_dbg("Trying to open LUKS2 keyslot %d.", keyslot);
|
||||
log_dbg(cd, "Trying to open LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
@@ -505,6 +537,10 @@ static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
volume_key, volume_key_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function must not modify json.
|
||||
* It's called after luks2 keyslot validation.
|
||||
*/
|
||||
static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
@@ -516,7 +552,7 @@ static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot;
|
||||
int r;
|
||||
|
||||
log_dbg("Calculating attributes for LUKS2 keyslot %d.", keyslot);
|
||||
log_dbg(cd, "Calculating attributes for LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
@@ -525,17 +561,19 @@ static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
|
||||
if(r)
|
||||
return r;
|
||||
|
||||
r = luks2_keyslot_set_key(cd, jobj_keyslot,
|
||||
password, password_len,
|
||||
volume_key, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
|
||||
return keyslot;
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_wipe(struct crypt_device *cd, int keyslot)
|
||||
@@ -568,6 +606,9 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
|
||||
log_std(cd, "\tCipher: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
|
||||
log_std(cd, "\tCipher key: %u bits\n", crypt_jobj_get_uint32(jobj1) * 8);
|
||||
|
||||
json_object_object_get_ex(jobj_kdf, "type", &jobj1);
|
||||
log_std(cd, "\tPBKDF: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
@@ -576,10 +617,10 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
log_std(cd, "\tHash: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_kdf, "iterations", &jobj1);
|
||||
log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_uint64(jobj1));
|
||||
log_std(cd, "\tIterations: %" PRIu64 "\n", crypt_jobj_get_uint64(jobj1));
|
||||
} else {
|
||||
json_object_object_get_ex(jobj_kdf, "time", &jobj1);
|
||||
log_std(cd, "\tTime: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
log_std(cd, "\tTime cost: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_kdf, "memory", &jobj1);
|
||||
log_std(cd, "\tMemory: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
@@ -595,68 +636,59 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
json_object_object_get_ex(jobj_af, "stripes", &jobj1);
|
||||
log_std(cd, "\tAF stripes: %u\n", json_object_get_int(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_af, "hash", &jobj1);
|
||||
log_std(cd, "\tAF hash: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj1);
|
||||
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
|
||||
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_area, "size", &jobj1);
|
||||
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
|
||||
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int contains(json_object *jobj, const char *key, json_type type)
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *sobj;
|
||||
json_object *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
const char *type;
|
||||
int count;
|
||||
|
||||
if (!json_object_object_get_ex(jobj, key, &sobj) ||
|
||||
!json_object_is_type(sobj, type))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
char num[16];
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
if (LUKS2_keyslot_validate(hdr->jobj, jobj_keyslot, num))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
count = json_object_object_length(jobj_kdf);
|
||||
|
||||
if (!strcmp(json_object_get_string(jobj1), CRYPT_KDF_PBKDF2)) {
|
||||
if (!contains(jobj_kdf, "hash", json_type_string) ||
|
||||
!contains(jobj_kdf, "iterations", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
jobj1 = json_contains(cd, jobj_kdf, "", "kdf section", "type", json_type_string);
|
||||
if (!jobj1)
|
||||
return -EINVAL;
|
||||
type = json_object_get_string(jobj1);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
if (count != 4 || /* type, salt, hash, iterations only */
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "hash", json_type_string) ||
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!contains(jobj_kdf, "time", json_type_int) ||
|
||||
!contains(jobj_kdf, "memory", json_type_int) ||
|
||||
!contains(jobj_kdf, "cpus", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
if (count != 5 || /* type, salt, time, memory, cpus only */
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "time", json_type_int) ||
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "memory", json_type_int) ||
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
|
||||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
|
||||
if (!contains(jobj_af, "hash", json_type_string) ||
|
||||
!contains(jobj_af, "stripes", json_type_int))
|
||||
if (!json_contains(cd, jobj_af, "", "luks1 af", "hash", json_type_string) ||
|
||||
!json_contains(cd, jobj_af, "", "luks1 af", "stripes", json_type_int))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -665,10 +697,10 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "raw")) {
|
||||
if (!contains(jobj_area, "encryption", json_type_string) ||
|
||||
!contains(jobj_area, "key_size", json_type_int) ||
|
||||
!contains(jobj_area, "offset", json_type_string) ||
|
||||
!contains(jobj_area, "size", json_type_string))
|
||||
if (!json_contains(cd, jobj_area, "area", "raw type", "encryption", json_type_string) ||
|
||||
!json_contains(cd, jobj_area, "area", "raw type", "key_size", json_type_int) ||
|
||||
!json_contains(cd, jobj_area, "area", "raw type", "offset", json_type_string) ||
|
||||
!json_contains(cd, jobj_area, "area", "raw type", "size", json_type_string))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -676,12 +708,78 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_update(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r;
|
||||
|
||||
log_dbg(cd, "Updating LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "Not enough space in header json area for updated keyslot %d.", keyslot);
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void luks2_keyslot_repair(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
const char *type;
|
||||
json_object *jobj_kdf, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_is_type(jobj_kdf, json_type_object))
|
||||
return;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
return;
|
||||
|
||||
type = json_object_get_string(jobj_type);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
/* type, salt, hash, iterations only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "hash") || !strcmp(key, "iterations"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
/* type, salt, time, memory, cpus only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "time") || !strcmp(key, "memory") ||
|
||||
!strcmp(key, "cpus"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyslot_handler luks2_keyslot = {
|
||||
.name = "luks2",
|
||||
.alloc = luks2_keyslot_alloc,
|
||||
.update = luks2_keyslot_update,
|
||||
.open = luks2_keyslot_open,
|
||||
.store = luks2_keyslot_store,
|
||||
.wipe = luks2_keyslot_wipe,
|
||||
.dump = luks2_keyslot_dump,
|
||||
.validate = luks2_keyslot_validate,
|
||||
.repair = luks2_keyslot_repair
|
||||
};
|
||||
|
||||
336
lib/luks2/luks2_keyslot_reenc.c
Normal file
336
lib/luks2/luks2_keyslot_reenc.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
|
||||
*
|
||||
* Copyright (C) 2016-2020, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2020, Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
static int reenc_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
char *volume_key,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
int r;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
uint64_t area_offset, area_length;
|
||||
|
||||
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
/* encryption doesn't require area (we shift data and backup will be available) */
|
||||
if (!params->data_shift) {
|
||||
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else { /* we can't have keyslot w/o area...bug? */
|
||||
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
if (!jobj_keyslot)
|
||||
return -ENOMEM;
|
||||
|
||||
jobj_area = json_object_new_object();
|
||||
|
||||
if (params->data_shift) {
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
|
||||
json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
|
||||
} else
|
||||
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
|
||||
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
|
||||
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
|
||||
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
|
||||
if (params->direction == CRYPT_REENCRYPT_FORWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
|
||||
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "New keyslot too large to fit in free metadata space.");
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
JSON_DBG(cd, hdr->jobj, "JSON:");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store_data(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const void *buffer, size_t buffer_len)
|
||||
{
|
||||
int devfd, r;
|
||||
json_object *jobj_area, *jobj_offset, *jobj_length;
|
||||
uint64_t area_offset, area_length;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
|
||||
!json_object_object_get_ex(jobj_area, "size", &jobj_length))
|
||||
return -EINVAL;
|
||||
|
||||
area_offset = crypt_jobj_get_uint64(jobj_offset);
|
||||
area_length = crypt_jobj_get_uint64(jobj_length);
|
||||
|
||||
if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), CONST_CAST(void *)buffer,
|
||||
buffer_len, area_offset) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
} else
|
||||
r = -EINVAL;
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password __attribute__((unused)),
|
||||
size_t password_len __attribute__((unused)),
|
||||
const char *buffer,
|
||||
size_t buffer_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r = 0;
|
||||
|
||||
if (!cd || !buffer || !buffer_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
|
||||
if (r < 0) {
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
|
||||
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
|
||||
|
||||
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
|
||||
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
|
||||
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
|
||||
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else
|
||||
log_dbg(cd, "No update of reencrypt keyslot needed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
|
||||
*jobj1;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
|
||||
return -EINVAL;
|
||||
|
||||
log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
|
||||
log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
|
||||
log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
|
||||
|
||||
if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
|
||||
json_object_object_get_ex(jobj_area, "hash", &jobj1);
|
||||
log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
|
||||
json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
|
||||
log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
|
||||
} else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
|
||||
json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
|
||||
log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", crypt_jobj_get_uint64(jobj1));
|
||||
}
|
||||
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj1);
|
||||
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_area, "size", &jobj1);
|
||||
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction;
|
||||
const char *mode, *type, *direction;
|
||||
uint32_t sector_size;
|
||||
uint64_t shift_size;
|
||||
|
||||
/* mode (string: encrypt,reencrypt,decrypt)
|
||||
* direction (string:)
|
||||
* area {
|
||||
* type: (string: datashift, journal, checksum, none)
|
||||
* hash: (string: checksum only)
|
||||
* sector_size (uint32: checksum only)
|
||||
* shift_size (uint64: datashift only)
|
||||
* }
|
||||
*/
|
||||
|
||||
/* area and area type are validated in general validation code */
|
||||
if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
|
||||
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
|
||||
|
||||
if (!jobj_mode || !jobj_direction)
|
||||
return -EINVAL;
|
||||
|
||||
mode = json_object_get_string(jobj_mode);
|
||||
type = json_object_get_string(jobj_type);
|
||||
direction = json_object_get_string(jobj_direction);
|
||||
|
||||
if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
|
||||
strcmp(mode, "decrypt")) {
|
||||
log_dbg(cd, "Illegal reencrypt mode %s.", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strcmp(direction, "forward") && strcmp(direction, "backward")) {
|
||||
log_dbg(cd, "Illegal reencrypt direction %s.", direction);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(type, "checksum")) {
|
||||
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
|
||||
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
|
||||
if (!jobj_hash || !jobj_sector_size)
|
||||
return -EINVAL;
|
||||
if (!validate_json_uint32(jobj_sector_size))
|
||||
return -EINVAL;
|
||||
sector_size = crypt_jobj_get_uint32(jobj_sector_size);
|
||||
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
|
||||
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strcmp(type, "datashift")) {
|
||||
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
|
||||
return -EINVAL;
|
||||
|
||||
shift_size = crypt_jobj_get_uint64(jobj_shift_size);
|
||||
if (!shift_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (MISALIGNED_512(shift_size)) {
|
||||
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const keyslot_handler reenc_keyslot = {
|
||||
.name = "reencrypt",
|
||||
.open = reenc_keyslot_open,
|
||||
.store = reenc_keyslot_store, /* initialization only or also per every chunk write */
|
||||
.wipe = reenc_keyslot_wipe,
|
||||
.dump = reenc_keyslot_dump,
|
||||
.validate = reenc_keyslot_validate
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Ondrej Kozina
|
||||
* Copyright (C) 2015-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,9 +24,17 @@
|
||||
#include "../luks1/luks.h"
|
||||
#include "../luks1/af.h"
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode)
|
||||
{
|
||||
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
|
||||
}
|
||||
|
||||
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
|
||||
{
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L], num[24];
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
size_t base64_len;
|
||||
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint64_t offset, area_size, offs_a, offs_b, length;
|
||||
@@ -83,8 +91,8 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
|
||||
}
|
||||
area_size = offs_b - offs_a;
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_string(uint64_to_str(num, sizeof(num), &area_size)));
|
||||
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
|
||||
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_size));
|
||||
json_object_object_add(keyslot_obj, "area", jobj_area);
|
||||
|
||||
*keyslot_object = keyslot_obj;
|
||||
@@ -93,24 +101,22 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
|
||||
|
||||
static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, struct json_object **keyslots_object)
|
||||
{
|
||||
char keyslot_str[2];
|
||||
int key_slot, r;
|
||||
int keyslot, r;
|
||||
struct json_object *keyslot_obj, *field;
|
||||
|
||||
keyslot_obj = json_object_new_object();
|
||||
if (!keyslot_obj)
|
||||
return -ENOMEM;
|
||||
|
||||
for (key_slot = 0; key_slot < LUKS_NUMKEYS; key_slot++) {
|
||||
if (hdr_v1->keyblock[key_slot].active != LUKS_KEY_ENABLED)
|
||||
for (keyslot = 0; keyslot < LUKS_NUMKEYS; keyslot++) {
|
||||
if (hdr_v1->keyblock[keyslot].active != LUKS_KEY_ENABLED)
|
||||
continue;
|
||||
r = json_luks1_keyslot(hdr_v1, key_slot, &field);
|
||||
r = json_luks1_keyslot(hdr_v1, keyslot, &field);
|
||||
if (r) {
|
||||
json_object_put(keyslot_obj);
|
||||
return r;
|
||||
}
|
||||
(void) snprintf(keyslot_str, sizeof(keyslot_str), "%d", key_slot);
|
||||
json_object_object_add(keyslot_obj, keyslot_str, field);
|
||||
json_object_object_add_by_uint(keyslot_obj, keyslot, field);
|
||||
}
|
||||
|
||||
*keyslots_object = keyslot_obj;
|
||||
@@ -121,7 +127,6 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
|
||||
{
|
||||
const char *c;
|
||||
char cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
char num[24]; /* uint64_t in string */
|
||||
struct json_object *segment_obj, *field;
|
||||
uint64_t number;
|
||||
|
||||
@@ -140,7 +145,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
|
||||
/* offset field */
|
||||
number = (uint64_t)hdr_v1->payloadOffset * SECTOR_SIZE;
|
||||
|
||||
field = json_object_new_string(uint64_to_str(num, sizeof(num), &number));
|
||||
field = crypt_jobj_new_uint64(number);
|
||||
if (!field) {
|
||||
json_object_put(segment_obj);
|
||||
return -ENOMEM;
|
||||
@@ -191,7 +196,6 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
|
||||
|
||||
static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_object **segments_object)
|
||||
{
|
||||
char num[16];
|
||||
int r;
|
||||
struct json_object *segments_obj, *field;
|
||||
|
||||
@@ -204,8 +208,7 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
|
||||
json_object_put(segments_obj);
|
||||
return r;
|
||||
}
|
||||
snprintf(num, sizeof(num), "%u", CRYPT_DEFAULT_SEGMENT);
|
||||
json_object_object_add(segments_obj, num, field);
|
||||
json_object_object_add_by_uint(segments_obj, 0, field);
|
||||
|
||||
*segments_object = segments_obj;
|
||||
return 0;
|
||||
@@ -348,7 +351,6 @@ static int json_luks1_digests(const struct luks_phdr *hdr_v1, struct json_object
|
||||
|
||||
static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks1_object, uint64_t keyslots_size)
|
||||
{
|
||||
char num[24];
|
||||
int r;
|
||||
struct json_object *luks1_obj, *field;
|
||||
uint64_t json_size;
|
||||
@@ -399,10 +401,9 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
|
||||
json_object_object_add(luks1_obj, "config", field);
|
||||
|
||||
json_size = LUKS2_HDR_16K_LEN - LUKS2_HDR_BIN_LEN;
|
||||
json_object_object_add(field, "json_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
|
||||
json_object_object_add(field, "keyslots_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
|
||||
json_object_object_add(field, "json_size", crypt_jobj_new_uint64(json_size));
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
json_object_object_add(field, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
|
||||
|
||||
*luks1_object = luks1_obj;
|
||||
return 0;
|
||||
@@ -410,7 +411,6 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
|
||||
|
||||
static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
{
|
||||
char num[24];
|
||||
json_object *jobj1, *jobj2, *jobj_area;
|
||||
uint64_t offset = 0;
|
||||
|
||||
@@ -419,8 +419,8 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
UNUSED(key);
|
||||
json_object_object_get_ex(val, "area", &jobj_area);
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj2);
|
||||
offset = json_object_get_uint64(jobj2) + offset_add;
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
offset = crypt_jobj_get_uint64(jobj2) + offset_add;
|
||||
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,86 +428,130 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
off_t offset_to, size_t buf_size)
|
||||
{
|
||||
int devfd, r = -EIO;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd = -1;
|
||||
|
||||
log_dbg("Moving keyslot areas of size %zu from %jd to %jd.",
|
||||
log_dbg(cd, "Moving keyslot areas of size %zu from %jd to %jd.",
|
||||
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
|
||||
|
||||
// FIXME: export aligned_malloc from utils
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), buf_size))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd == -1) {
|
||||
log_dbg("Cannot open device %s.", device_path(device));
|
||||
devfd = device_open(cd, device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
/* This can safely fail (for block devices). It only allocates space if it is possible. */
|
||||
if (posix_fallocate(devfd, offset_to, buf_size))
|
||||
log_dbg(cd, "Preallocation (fallocate) of new keyslot area not available.");
|
||||
|
||||
/* Try to read *new* area to check that area is there (trimmed backup). */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_from)!= (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_to)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_from)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_to) != (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_to) != (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
close(devfd);
|
||||
crypt_memzero(buf, buf_size);
|
||||
r = 0;
|
||||
out:
|
||||
device_sync(cd, device);
|
||||
crypt_safe_memzero(buf, buf_size);
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks_header_in_use(struct crypt_device *cd)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = lookup_dm_dev_by_uuid(crypt_get_uuid(cd), crypt_get_type(cd));
|
||||
r = lookup_dm_dev_by_uuid(cd, crypt_get_uuid(cd), crypt_get_type(cd));
|
||||
if (r < 0)
|
||||
log_err(cd, _("Can not check status of device with uuid: %s.\n"), crypt_get_uuid(cd));
|
||||
log_err(cd, _("Cannot check status of device with uuid: %s."), crypt_get_uuid(cd));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
|
||||
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
|
||||
{
|
||||
int devfd, r = 0;
|
||||
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(cd, device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Note: we must not detect failure as problem here, header can be trimmed. */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device),
|
||||
buf, sizeof(LM_MAGIC), luks1_size) == (ssize_t)sizeof(LM_MAGIC) &&
|
||||
!memcmp(LM_MAGIC, buf, sizeof(LM_MAGIC))) {
|
||||
log_err(cd, _("Unable to convert header with LUKSMETA additional metadata."));
|
||||
r = -EBUSY;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert LUKS1 -> LUKS2 */
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct luks2_hdr *hdr2)
|
||||
{
|
||||
int r;
|
||||
json_object *jobj = NULL;
|
||||
size_t buf_size, buf_offset, luks1_size, luks1_shift = 2 * LUKS2_HDR_16K_LEN - LUKS_ALIGN_KEYSLOTS;
|
||||
uint64_t max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
|
||||
uint64_t required_size, max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
|
||||
|
||||
/* for detached headers max size == device size */
|
||||
if (!max_size && (r = device_size(crypt_metadata_device(cd), &max_size)))
|
||||
return r;
|
||||
|
||||
luks1_size = LUKS_device_sectors(hdr1) << SECTOR_SHIFT;
|
||||
luks1_size = size_round_up(luks1_size, LUKS_ALIGN_KEYSLOTS);
|
||||
if (!luks1_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS_keyslots_offset(hdr1) != (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
|
||||
log_dbg("Unsupported keyslots material offset: %zu.", LUKS_keyslots_offset(hdr1));
|
||||
log_dbg(cd, "Unsupported keyslots material offset: %zu.", LUKS_keyslots_offset(hdr1));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg("Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
|
||||
if (luksmeta_header_present(cd, luks1_size))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
|
||||
max_size, luks1_size, luks1_shift);
|
||||
if ((max_size - luks1_size) < luks1_shift) {
|
||||
log_err(cd, _("Unable to move keyslot materials. Not enough space\n"));
|
||||
|
||||
required_size = luks1_size + luks1_shift;
|
||||
|
||||
if ((max_size < required_size) &&
|
||||
device_fallocate(crypt_metadata_device(cd), required_size)) {
|
||||
log_err(cd, _("Unable to move keyslot area. Not enough space."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (max_size < required_size)
|
||||
max_size = required_size;
|
||||
|
||||
r = json_luks1_object(hdr1, &jobj, max_size - 2 * LUKS2_HDR_16K_LEN);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -534,6 +578,12 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check future LUKS2 metadata before moving keyslots area */
|
||||
if (LUKS2_hdr_validate(cd, hdr2->jobj, hdr2->hdr_size - LUKS2_HDR_BIN_LEN)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = luks_header_in_use(cd))) {
|
||||
if (r > 0)
|
||||
r = -EBUSY;
|
||||
@@ -543,22 +593,34 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
// move keyslots 4k -> 32k offset
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0)
|
||||
|
||||
/* check future LUKS2 keyslots area is at least as large as LUKS1 keyslots area */
|
||||
if (buf_size > LUKS2_keyslots_size(hdr2->jobj)) {
|
||||
log_err(cd, _("Unable to move keyslot area. LUKS2 keyslots area too small."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Write JSON hdr2
|
||||
r = LUKS2_hdr_write(cd, hdr2);
|
||||
out:
|
||||
LUKS2_hdr_free(hdr2);
|
||||
LUKS2_hdr_free(cd, hdr2);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t key_size)
|
||||
static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, uint32_t key_size, const char *hash)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj, *jobj_kdf, *jobj_af;
|
||||
uint64_t l2_offset, l2_length;
|
||||
int ks_key_size;
|
||||
size_t ks_key_size;
|
||||
const char *ks_cipher, *data_cipher;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
@@ -572,7 +634,9 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
jobj = NULL;
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_kdf, "type", &jobj) ||
|
||||
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2))
|
||||
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2) ||
|
||||
!json_object_object_get_ex(jobj_kdf, "hash", &jobj) ||
|
||||
strcmp(json_object_get_string(jobj), hash))
|
||||
return 0;
|
||||
|
||||
jobj = NULL;
|
||||
@@ -583,13 +647,16 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
|
||||
jobj = NULL;
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj) ||
|
||||
crypt_hash_size(json_object_get_string(jobj)) < 0)
|
||||
(crypt_hash_size(json_object_get_string(jobj)) < 0) ||
|
||||
strcmp(json_object_get_string(jobj), hash))
|
||||
return 0;
|
||||
|
||||
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
|
||||
ks_key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
|
||||
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_key_size(hdr, keyslot)) {
|
||||
log_dbg("Key length in keyslot %d is different from volume key length", keyslot);
|
||||
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
|
||||
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
|
||||
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
|
||||
if (!ks_cipher || !data_cipher || key_size != ks_key_size || strcmp(ks_cipher, data_cipher)) {
|
||||
log_dbg(cd, "Cipher in keyslot %d is different from volume key encryption.", keyslot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -597,7 +664,7 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
return 0;
|
||||
|
||||
if (l2_length != (size_round_up(AF_split_sectors(key_size, LUKS_STRIPES) * SECTOR_SIZE, 4096))) {
|
||||
log_dbg("Area length in LUKS2 keyslot (%d) is not compatible with LUKS1", keyslot);
|
||||
log_dbg(cd, "Area length in LUKS2 keyslot (%d) is not compatible with LUKS1", keyslot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -608,8 +675,9 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct luks_phdr *hdr1)
|
||||
{
|
||||
size_t buf_size, buf_offset;
|
||||
char cipher[LUKS_CIPHERNAME_L], cipher_mode[LUKS_CIPHERMODE_L];
|
||||
char cipher[LUKS_CIPHERNAME_L-1], cipher_mode[LUKS_CIPHERMODE_L-1];
|
||||
char digest[LUKS_DIGESTSIZE], digest_salt[LUKS_SALTSIZE];
|
||||
const char *hash;
|
||||
size_t len;
|
||||
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
|
||||
uint32_t key_size;
|
||||
@@ -625,34 +693,60 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
if (!jobj_segment)
|
||||
return -EINVAL;
|
||||
|
||||
if (json_segment_get_sector_size(jobj_segment) != SECTOR_SIZE) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - default segment encryption sector size is not 512 bytes."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(hdr2->jobj, "digests", &jobj1);
|
||||
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
|
||||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
|
||||
json_object_object_length(jobj1) != 1) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible.\n"));
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!json_object_object_get_ex(jobj_digest, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
hash = json_object_get_string(jobj2);
|
||||
|
||||
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_cipher_wrapped_key(cipher, cipher_mode)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - device uses wrapped key cipher %s."), cipher);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_size = r = LUKS2_get_volume_key_size(hdr2, 0);
|
||||
r = LUKS2_tokens_count(hdr2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - LUKS2 header contains %u token(s)."), r);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_get_volume_key_size(hdr2, 0);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
key_size = r;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
|
||||
continue;
|
||||
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i >= LUKS_NUMKEYS) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active .\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!keyslot_LUKS1_compatible(hdr2, i, key_size)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible.\n"), i);
|
||||
if (!keyslot_LUKS1_compatible(cd, hdr2, i, key_size, hash)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -670,12 +764,16 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
return -EINVAL;
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj1))
|
||||
return -EINVAL;
|
||||
offset = json_object_get_uint64(jobj1);
|
||||
offset = crypt_jobj_get_uint64(jobj1);
|
||||
} else {
|
||||
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
|
||||
return -EINVAL;
|
||||
/* FIXME: luks2 reload is required! */
|
||||
if (luks2_keyslot_alloc(cd, i, key_size))
|
||||
/*
|
||||
* We have to create placeholder luks2 keyslots in place of all
|
||||
* inactive keyslots. Otherwise we would allocate all
|
||||
* inactive luks1 keyslots over same binary keyslot area.
|
||||
*/
|
||||
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -698,7 +796,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj1))
|
||||
continue;
|
||||
hdr1->keyblock[i].passwordIterations = json_object_get_uint32(jobj1);
|
||||
hdr1->keyblock[i].passwordIterations = crypt_jobj_get_uint32(jobj1);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj1))
|
||||
continue;
|
||||
@@ -739,7 +837,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
|
||||
if (!json_object_object_get_ex(jobj_digest, "iterations", &jobj1))
|
||||
return -EINVAL;
|
||||
hdr1->mkDigestIterations = json_object_get_uint32(jobj1);
|
||||
hdr1->mkDigestIterations = crypt_jobj_get_uint32(jobj1);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
|
||||
return -EINVAL;
|
||||
@@ -764,13 +862,14 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segment, "offset", &jobj1))
|
||||
return -EINVAL;
|
||||
offset = json_object_get_uint64(jobj1) / SECTOR_SIZE;
|
||||
offset = crypt_jobj_get_uint64(jobj1) / SECTOR_SIZE;
|
||||
if (offset > UINT32_MAX)
|
||||
return -EINVAL;
|
||||
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
|
||||
hdr1->payloadOffset = offset;
|
||||
|
||||
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L - 1); /* max 36 chars */
|
||||
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L); /* max 36 chars */
|
||||
hdr1->uuid[UUID_STRING_L-1] = '\0';
|
||||
|
||||
memcpy(hdr1->magic, luksMagic, LUKS_MAGIC_L);
|
||||
|
||||
@@ -784,8 +883,10 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = LUKS2_keyslots_size(hdr2->jobj);
|
||||
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
return r;
|
||||
}
|
||||
|
||||
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
|
||||
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);
|
||||
|
||||
3445
lib/luks2/luks2_reencrypt.c
Normal file
3445
lib/luks2/luks2_reencrypt.c
Normal file
File diff suppressed because it is too large
Load Diff
412
lib/luks2/luks2_segment.c
Normal file
412
lib/luks2/luks2_segment.c
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, internal segment handling
|
||||
*
|
||||
* Copyright (C) 2018-2020, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2020, Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
/* use only on already validated 'segments' object */
|
||||
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
|
||||
{
|
||||
uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
|
||||
|
||||
if (!jobj_segments)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, val) {
|
||||
UNUSED(key);
|
||||
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
|
||||
tmp = json_segment_get_offset(val, blockwise);
|
||||
|
||||
if (!tmp)
|
||||
return tmp;
|
||||
|
||||
if (tmp < min)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "offset", &jobj))
|
||||
return 0;
|
||||
|
||||
return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
|
||||
}
|
||||
|
||||
const char *json_segment_type(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "type", &jobj))
|
||||
return NULL;
|
||||
|
||||
return json_object_get_string(jobj);
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
|
||||
return 0;
|
||||
|
||||
return crypt_jobj_get_uint64(jobj);
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "size", &jobj))
|
||||
return 0;
|
||||
|
||||
return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
|
||||
}
|
||||
|
||||
const char *json_segment_get_cipher(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
/* FIXME: Pseudo "null" cipher should be handled elsewhere */
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "encryption", &jobj))
|
||||
return "null";
|
||||
|
||||
return json_object_get_string(jobj);
|
||||
}
|
||||
|
||||
int json_segment_get_sector_size(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
|
||||
return -1;
|
||||
|
||||
return json_object_get_int(jobj);
|
||||
}
|
||||
|
||||
static json_object *json_segment_get_flags(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
|
||||
return NULL;
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
{
|
||||
int r, i;
|
||||
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
|
||||
if (!jobj_flags)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_flags, i);
|
||||
if (len)
|
||||
r = strncmp(json_object_get_string(jobj), flag_str, len);
|
||||
else
|
||||
r = strcmp(json_object_get_string(jobj), flag_str);
|
||||
if (!r)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_segment_is_backup(json_object *jobj_segment)
|
||||
{
|
||||
return json_segment_contains_flag(jobj_segment, "backup-", 7);
|
||||
}
|
||||
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
char segment_name[16];
|
||||
|
||||
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
|
||||
return NULL;
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
unsigned json_segments_count(json_object *jobj_segments)
|
||||
{
|
||||
unsigned count = 0;
|
||||
|
||||
if (!jobj_segments)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!json_segment_is_backup(val))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
|
||||
{
|
||||
json_object *jobj_flags, **jobj_ret = (json_object **)retval;
|
||||
int *ret = (int *)retval;
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, value) {
|
||||
if (!json_object_object_get_ex(value, "flags", &jobj_flags))
|
||||
continue;
|
||||
if (LUKS2_array_jobj(jobj_flags, flag)) {
|
||||
if (id)
|
||||
*ret = atoi(key);
|
||||
else
|
||||
*jobj_ret = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
|
||||
{
|
||||
json_object *jobj_flags, *jobj_flags_new;
|
||||
|
||||
if (!jobj_segment)
|
||||
return;
|
||||
|
||||
jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
if (!jobj_flags)
|
||||
return;
|
||||
|
||||
jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
|
||||
if (!jobj_flags_new)
|
||||
return;
|
||||
|
||||
if (json_object_array_length(jobj_flags_new) <= 0) {
|
||||
json_object_put(jobj_flags_new);
|
||||
json_object_object_del(jobj_segment, "flags");
|
||||
} else
|
||||
json_object_object_add(jobj_segment, "flags", jobj_flags_new);
|
||||
}
|
||||
|
||||
static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
|
||||
{
|
||||
json_object *jobj = json_object_new_object();
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
json_object_object_add(jobj, "type", json_object_new_string(type));
|
||||
json_object_object_add(jobj, "offset", crypt_jobj_new_uint64(offset));
|
||||
json_object_object_add(jobj, "size", length ? crypt_jobj_new_uint64(*length) : json_object_new_string("dynamic"));
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
|
||||
{
|
||||
json_object *jobj = _segment_create_generic("linear", offset, length);
|
||||
if (reencryption)
|
||||
LUKS2_segment_set_flag(jobj, "in-reencryption");
|
||||
return jobj;
|
||||
}
|
||||
|
||||
json_object *json_segment_create_crypt(uint64_t offset,
|
||||
uint64_t iv_offset, const uint64_t *length,
|
||||
const char *cipher, uint32_t sector_size,
|
||||
unsigned reencryption)
|
||||
{
|
||||
json_object *jobj = _segment_create_generic("crypt", offset, length);
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
json_object_object_add(jobj, "iv_tweak", crypt_jobj_new_uint64(iv_offset));
|
||||
json_object_object_add(jobj, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
|
||||
if (reencryption)
|
||||
LUKS2_segment_set_flag(jobj, "in-reencryption");
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
|
||||
{
|
||||
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
|
||||
}
|
||||
|
||||
int json_segments_segment_in_reencrypt(json_object *jobj_segments)
|
||||
{
|
||||
json_object *jobj_flags;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
|
||||
!LUKS2_array_jobj(jobj_flags, "in-reencryption"))
|
||||
continue;
|
||||
|
||||
return atoi(slot);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
|
||||
{
|
||||
return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
|
||||
}
|
||||
|
||||
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
|
||||
{
|
||||
return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
|
||||
}
|
||||
|
||||
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int last_found = -1;
|
||||
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -1;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
|
||||
if (atoi(slot) > last_found)
|
||||
last_found = atoi(slot);
|
||||
}
|
||||
|
||||
return last_found;
|
||||
}
|
||||
|
||||
int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int first_found = -1;
|
||||
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
|
||||
if (first_found < 0)
|
||||
first_found = atoi(slot);
|
||||
else if (atoi(slot) < first_found)
|
||||
first_found = atoi(slot);
|
||||
}
|
||||
|
||||
return first_found;
|
||||
}
|
||||
|
||||
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int id, last_id = -1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
UNUSED(val);
|
||||
id = atoi(slot);
|
||||
if (id > last_id)
|
||||
last_id = id;
|
||||
}
|
||||
|
||||
return last_id + 1;
|
||||
}
|
||||
|
||||
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
|
||||
{
|
||||
json_object *jobj_flags;
|
||||
|
||||
if (!jobj_segment || !flag)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
|
||||
jobj_flags = json_object_new_array();
|
||||
if (!jobj_flags)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_segment, "flags", jobj_flags);
|
||||
}
|
||||
|
||||
if (LUKS2_array_jobj(jobj_flags, flag))
|
||||
return 0;
|
||||
|
||||
json_object_array_add(jobj_flags, json_object_new_string(flag));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj_segments, int commit)
|
||||
{
|
||||
json_object_object_add(hdr->jobj, "segments", jobj_segments);
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
|
||||
|
||||
if (jobj_segments)
|
||||
_get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
{
|
||||
json_object *jobj_segment = NULL,
|
||||
*jobj_segments = LUKS2_get_segments_jobj(hdr);
|
||||
|
||||
if (jobj_segments)
|
||||
_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
|
||||
|
||||
return jobj_segment;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, token handling
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2020 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -45,21 +45,19 @@ int crypt_token_register(const crypt_token_handler *handler)
|
||||
int i;
|
||||
|
||||
if (is_builtin_candidate(handler->name)) {
|
||||
log_dbg("'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix for builtin tokens.");
|
||||
log_dbg(NULL, "'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix for builtin tokens.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) {
|
||||
if (!strcmp(token_handlers[i].h->name, handler->name)) {
|
||||
log_dbg("Keyslot handler %s is already registered.", handler->name);
|
||||
log_dbg(NULL, "Keyslot handler %s is already registered.", handler->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == LUKS2_TOKENS_MAX) {
|
||||
log_dbg("No more space for another token handler.");
|
||||
if (i == LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
token_handlers[i].h = handler;
|
||||
return 0;
|
||||
@@ -132,6 +130,7 @@ int LUKS2_token_create(struct crypt_device *cd,
|
||||
int commit)
|
||||
{
|
||||
const crypt_token_handler *h;
|
||||
const token_handler *th;
|
||||
json_object *jobj_tokens, *jobj_type, *jobj;
|
||||
enum json_tokener_error jerr;
|
||||
char num[16];
|
||||
@@ -148,41 +147,45 @@ int LUKS2_token_create(struct crypt_device *cd,
|
||||
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(num, sizeof(num), "%d", token);
|
||||
|
||||
/* Remove token */
|
||||
if (!json) {
|
||||
snprintf(num, sizeof(num), "%d", token);
|
||||
if (!json)
|
||||
json_object_object_del(jobj_tokens, num);
|
||||
} else {
|
||||
else {
|
||||
|
||||
jobj = json_tokener_parse_verbose(json, &jerr);
|
||||
if (!jobj) {
|
||||
log_dbg("Token JSON parse failed.");
|
||||
log_dbg(cd, "Token JSON parse failed.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(num, sizeof(num), "%d", token);
|
||||
|
||||
if (LUKS2_token_validate(hdr->jobj, jobj, num)) {
|
||||
if (LUKS2_token_validate(cd, hdr->jobj, jobj, num)) {
|
||||
json_object_put(jobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(jobj, "type", &jobj_type);
|
||||
if (is_builtin_candidate(json_object_get_string(jobj_type))) {
|
||||
log_dbg("%s is builtin token candidate", json_object_get_string(jobj_type));
|
||||
json_object_put(jobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
th = LUKS2_token_handler_type_internal(cd, json_object_get_string(jobj_type));
|
||||
if (!th || !th->set) {
|
||||
log_dbg(cd, "%s is builtin token candidate with missing handler", json_object_get_string(jobj_type));
|
||||
json_object_put(jobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
h = th->h;
|
||||
} else
|
||||
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
|
||||
|
||||
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
|
||||
if (h && h->validate && h->validate(cd, json)) {
|
||||
json_object_put(jobj);
|
||||
log_dbg(cd, "Token type %s validation failed.", h->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_tokens, num, jobj);
|
||||
if (LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for new token.");
|
||||
if (LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "Not enough space in header json area for new token.");
|
||||
json_object_object_del(jobj_tokens, num);
|
||||
return -ENOSPC;
|
||||
}
|
||||
@@ -246,7 +249,6 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
int commit)
|
||||
{
|
||||
const token_handler *th;
|
||||
char num[16];
|
||||
int r;
|
||||
json_object *jobj_token, *jobj_tokens;
|
||||
|
||||
@@ -257,29 +259,29 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
|
||||
if (token == CRYPT_ANY_TOKEN) {
|
||||
if ((token = LUKS2_token_find_free(hdr)) < 0)
|
||||
log_err(cd, _("No free token slot\n"));
|
||||
log_err(cd, _("No free token slot."));
|
||||
}
|
||||
if (token < 0 || token >= LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
snprintf(num, sizeof(num), "%u", token);
|
||||
|
||||
r = th->set(&jobj_token, params);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to create builtin token %s\n"), type);
|
||||
log_err(cd, _("Failed to create builtin token %s."), type);
|
||||
return r;
|
||||
}
|
||||
|
||||
// builtin tokens must produce valid json
|
||||
r = LUKS2_token_validate(hdr->jobj, jobj_token, "new");
|
||||
r = LUKS2_token_validate(cd, hdr->jobj, jobj_token, "new");
|
||||
assert(!r);
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
assert(!r);
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
|
||||
json_object_object_add(jobj_tokens, num, jobj_token);
|
||||
if (LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for new %s token.", type);
|
||||
json_object_object_del(jobj_tokens, num);
|
||||
json_object_object_add_by_uint(jobj_tokens, token, jobj_token);
|
||||
if (LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "Not enough space in header json area for new %s token.", type);
|
||||
json_object_object_del_by_uint(jobj_tokens, token);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -308,14 +310,14 @@ static int LUKS2_token_open(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
|
||||
if (h->validate(cd, json)) {
|
||||
log_dbg("Token %d (%s) validation failed.", token, h->name);
|
||||
log_dbg(cd, "Token %d (%s) validation failed.", token, h->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = h->open(cd, token, buffer, buffer_len, usrptr);
|
||||
if (r < 0)
|
||||
log_dbg("Token %d (%s) open failed with %d.", token, h->name, r);
|
||||
log_dbg(cd, "Token %d (%s) open failed with %d.", token, h->name, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -330,7 +332,7 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd,
|
||||
if (h->buffer_free)
|
||||
h->buffer_free(buffer, buffer_len);
|
||||
else {
|
||||
crypt_memzero(buffer, buffer_len);
|
||||
crypt_safe_memzero(buffer, buffer_len);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
@@ -345,7 +347,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
{
|
||||
const crypt_token_handler *h;
|
||||
json_object *jobj_token, *jobj_token_keyslots, *jobj;
|
||||
const char *num;
|
||||
unsigned int num = 0;
|
||||
int i, r;
|
||||
|
||||
if (!(h = LUKS2_token_handler(cd, token)))
|
||||
@@ -361,14 +363,17 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
|
||||
/* Try to open keyslot referenced in token */
|
||||
r = -EINVAL;
|
||||
for (i = 0; i < json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
|
||||
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
|
||||
num = json_object_get_string(jobj);
|
||||
log_dbg("Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
|
||||
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
|
||||
num = atoi(json_object_get_string(jobj));
|
||||
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", num, token, h->name);
|
||||
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
|
||||
}
|
||||
|
||||
return r < 0 ? r : atoi(num);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
@@ -388,7 +393,8 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
@@ -398,12 +404,16 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
|
||||
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -431,7 +441,8 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
continue;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
if (r >= 0)
|
||||
@@ -440,12 +451,16 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
|
||||
keyslot = r;
|
||||
|
||||
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
|
||||
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -460,7 +475,8 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
|
||||
if (h && h->dump) {
|
||||
jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token);
|
||||
if (jobj_token)
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +489,8 @@ int LUKS2_token_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (!jobj_token)
|
||||
return -EINVAL;
|
||||
|
||||
*json = json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN);
|
||||
*json = json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -483,7 +500,7 @@ static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj1, *jobj_token, *jobj_token_keyslots;
|
||||
char num[16];
|
||||
|
||||
log_dbg("Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token);
|
||||
log_dbg(cd, "Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token);
|
||||
|
||||
jobj_token = LUKS2_get_token_jobj(hdr, token);
|
||||
if (!jobj_token)
|
||||
@@ -558,3 +575,36 @@ int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, int token)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_token, *jobj_token_keyslots, *jobj;
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
jobj_token = LUKS2_get_token_jobj(hdr, token);
|
||||
if (!jobj_token)
|
||||
return -ENOENT;
|
||||
|
||||
json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots);
|
||||
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
|
||||
if (keyslot == atoi(json_object_get_string(jobj)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
|
||||
if (!jobj_tokens)
|
||||
return -EINVAL;
|
||||
|
||||
return json_object_object_length(jobj_tokens);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, kernel keyring token
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2020 Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,6 +31,7 @@ static int keyring_open(struct crypt_device *cd,
|
||||
{
|
||||
json_object *jobj_token, *jobj_key;
|
||||
struct luks2_hdr *hdr;
|
||||
int r;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
@@ -41,9 +42,14 @@ static int keyring_open(struct crypt_device *cd,
|
||||
|
||||
json_object_object_get_ex(jobj_token, "key_description", &jobj_key);
|
||||
|
||||
/* TODO: if r == -ENOKEY then instantiate the key? */
|
||||
if (keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len))
|
||||
r = keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len);
|
||||
if (r == -ENOTSUP) {
|
||||
log_dbg(cd, "Kernel keyring features disabled.");
|
||||
return -EINVAL;
|
||||
} else if (r < 0) {
|
||||
log_dbg(cd, "keyring_get_passphrase failed (error %d)", r);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -55,21 +61,26 @@ static int keyring_validate(struct crypt_device *cd __attribute__((unused)),
|
||||
json_object *jobj_token, *jobj_key;
|
||||
int r = 1;
|
||||
|
||||
log_dbg("Validating keyring token json");
|
||||
log_dbg(cd, "Validating keyring token json");
|
||||
|
||||
jobj_token = json_tokener_parse_verbose(json, &jerr);
|
||||
if (!jobj_token) {
|
||||
log_dbg("Keyring token JSON parse failed.");
|
||||
log_dbg(cd, "Keyring token JSON parse failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (json_object_object_length(jobj_token) != 3) {
|
||||
log_dbg(cd, "Keyring token is expected to have exactly 3 fields.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_token, "key_description", &jobj_key)) {
|
||||
log_dbg("missing key_description field.");
|
||||
log_dbg(cd, "missing key_description field.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_is_type(jobj_key, json_type_string)) {
|
||||
log_dbg("key_description is not a string.");
|
||||
log_dbg(cd, "key_description is not a string.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
15
lib/random.c
15
lib/random.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* cryptsetup kernel RNG access functions
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/select.h>
|
||||
@@ -28,10 +27,6 @@
|
||||
#include "libcryptsetup.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
static int random_initialised = 0;
|
||||
|
||||
#define URANDOM_DEVICE "/dev/urandom"
|
||||
@@ -167,13 +162,13 @@ int crypt_random_init(struct crypt_device *ctx)
|
||||
goto fail;
|
||||
|
||||
if (crypt_fips_mode())
|
||||
log_verbose(ctx, _("Running in FIPS mode.\n"));
|
||||
log_verbose(ctx, _("Running in FIPS mode."));
|
||||
|
||||
random_initialised = 1;
|
||||
return 0;
|
||||
fail:
|
||||
crypt_random_exit();
|
||||
log_err(ctx, _("Fatal error during RNG initialisation.\n"));
|
||||
log_err(ctx, _("Fatal error during RNG initialisation."));
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
@@ -210,12 +205,12 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_err(ctx, _("Unknown RNG quality requested.\n"));
|
||||
log_err(ctx, _("Unknown RNG quality requested."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (status)
|
||||
log_err(ctx, _("Error reading from RNG.\n"));
|
||||
log_err(ctx, _("Error reading from RNG."));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user