mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-08 01:10:03 +01:00
Compare commits
1069 Commits
v2.0.0-rc0
...
v2.3.0-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
16da1a5c88 | ||
|
|
e514d1201d | ||
|
|
eb0293a637 | ||
|
|
03581fc8cc | ||
|
|
246cf0df26 | ||
|
|
cf1d6461cb | ||
|
|
9bcc97bc5e | ||
|
|
3bc124d9d3 | ||
|
|
764ae2a489 | ||
|
|
e678d5ae8e | ||
|
|
13b1720899 | ||
|
|
35512f4ee9 | ||
|
|
e55f10a8f1 | ||
|
|
b187e499a4 | ||
|
|
dd397a9957 | ||
|
|
cdfed8fabc | ||
|
|
759577ad9b | ||
|
|
356402942f | ||
|
|
76947fa835 | ||
|
|
f7dadfb646 | ||
|
|
4e31595c7a | ||
|
|
31779c0763 | ||
|
|
6e3622e0f1 | ||
|
|
b78bd4ccce | ||
|
|
a10059d531 | ||
|
|
1f2ce01c08 | ||
|
|
fb5a70a663 | ||
|
|
d62d0ed076 | ||
|
|
a4b9ce13ee | ||
|
|
43ee152eb4 | ||
|
|
fee909deee | ||
|
|
702bcb8684 | ||
|
|
961e65424e | ||
|
|
f901cb7b25 | ||
|
|
1d9d248456 | ||
|
|
86ef5475b9 | ||
|
|
087c314154 | ||
|
|
956ea10f56 | ||
|
|
4a4faa5d46 | ||
|
|
7e2a3fda4d | ||
|
|
786e51ecd1 | ||
|
|
d77bbe93c1 | ||
|
|
892b80ffa4 | ||
|
|
1c2cc9f35c | ||
|
|
12908709bb | ||
|
|
b42d183b08 | ||
|
|
e1ed664adc | ||
|
|
de2f07b82f | ||
|
|
cc5c91158d | ||
|
|
8dc35a7906 | ||
|
|
7e53c87f5c | ||
|
|
59e6b33c6f |
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
|
||||
|
||||
@@ -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,30 @@ 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 check
|
||||
}
|
||||
|
||||
#sudo $MAKE install || return
|
||||
function check_nonroot_compile_only
|
||||
{
|
||||
local cfg_opts="$1"
|
||||
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE
|
||||
}
|
||||
|
||||
function travis_install_script
|
||||
@@ -87,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 \
|
||||
@@ -105,6 +101,7 @@ function travis_install_script
|
||||
expect \
|
||||
keyutils \
|
||||
libjson-c-dev \
|
||||
libblkid-dev \
|
||||
|| return
|
||||
}
|
||||
|
||||
@@ -126,14 +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>
|
||||
|
||||
10
FAQ
10
FAQ
@@ -128,7 +128,7 @@ A. Contributors
|
||||
recommended to not install Ubuntu on a system with existing LUKS
|
||||
containers without complete backups.
|
||||
|
||||
Update 11/2014: There seem to be other problems withe existing LUKS
|
||||
Update 11/2014: There seem to be other problems with existing LUKS
|
||||
containers and Ubuntu as well, be extra careful when using LUKS
|
||||
on Ubuntu in any way, but exactly as the Ubuntu installer does.
|
||||
|
||||
@@ -209,7 +209,7 @@ A. Contributors
|
||||
to send it from your list address.
|
||||
|
||||
The mailing list archive is here:
|
||||
http://dir.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt
|
||||
https://marc.info/?l=dm-crypt
|
||||
|
||||
|
||||
* 1.8 Unsubscribe from the mailing-list
|
||||
@@ -976,7 +976,7 @@ A. Contributors
|
||||
|
||||
In order to find out whether a key-slot is damaged one has to look
|
||||
for "non-random looking" data in it. There is a tool that
|
||||
automatizes this in the cryptsetup distribution from version 1.6.0
|
||||
automates this in the cryptsetup distribution from version 1.6.0
|
||||
onwards. It is located in misc/keyslot_checker/. Instructions how
|
||||
to use and how to interpret results are in the README file. Note
|
||||
that this tool requires a libcryptsetup from cryptsetup 1.6.0 or
|
||||
@@ -2475,7 +2475,7 @@ offset length name data type description
|
||||
|
||||
More details:
|
||||
|
||||
Cipher, mode and pasword hash (or no hash):
|
||||
Cipher, mode and password hash (or no hash):
|
||||
|
||||
-e cipher [-N] => -c cipher-cbc-plain -H plain [-s 256]
|
||||
-e cipher => -c cipher-cbc-plain -H ripemd160 [-s 256]
|
||||
@@ -2616,7 +2616,7 @@ My take is this was much more driven by some big egos that wanted
|
||||
to make a splash for self-aggrandizement, than by any actual
|
||||
security concerns. Ignore it.
|
||||
|
||||
* 9.3 How do I do my own inird with cryptsetup?
|
||||
* 9.3 How do I do my own initrd with cryptsetup?
|
||||
|
||||
It depends on the distribution. Below, I give a very simple example
|
||||
and step-by-step instructions for Debian. With a bit of work, it
|
||||
|
||||
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.
|
||||
|
||||
54
Makefile.am
54
Makefile.am
@@ -1,14 +1,50 @@
|
||||
EXTRA_DIST = COPYING.LGPL FAQ docs misc
|
||||
SUBDIRS = \
|
||||
lib \
|
||||
src \
|
||||
man \
|
||||
python \
|
||||
tests \
|
||||
po \
|
||||
scripts
|
||||
SUBDIRS = po tests
|
||||
CLEANFILES =
|
||||
DISTCLEAN_TARGETS =
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-include config.h \
|
||||
-I$(top_srcdir)/lib \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
-DLOCALEDIR=\""$(datadir)/locale"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DSYSCONFDIR=\""$(sysconfdir)"\" \
|
||||
-DVERSION=\""$(VERSION)"\"
|
||||
AM_CFLAGS = -Wall
|
||||
AM_LDFLAGS =
|
||||
|
||||
LDADD = $(LTLIBINTL) -lm
|
||||
|
||||
tmpfilesddir = @DEFAULT_TMPFILESDIR@
|
||||
|
||||
noinst_LTLIBRARIES =
|
||||
sbin_PROGRAMS =
|
||||
man8_MANS =
|
||||
tmpfilesd_DATA =
|
||||
|
||||
include man/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
|
||||
|
||||
include src/Makemodule.am
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--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,28 +2,33 @@
|
||||
|
||||
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.
|
||||
and **TrueCrypt** (including **VeraCrypt** extension) formats.
|
||||
|
||||
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.
|
||||
|
||||
Project also includes **veritysetup** utility used to conveniently setup
|
||||
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module.
|
||||
|
||||
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,
|
||||
@@ -32,12 +37,6 @@ Why LUKS?
|
||||
[Project home page](https://gitlab.com/cryptsetup/cryptsetup/).
|
||||
-----------------
|
||||
|
||||
**CVE-2016-4484 (Initrd root shell)**
|
||||
|
||||
This is problem in **intramfs** **scripts** only (these are **not** part of cryptsetup project), it is neiter bug in cryptsetup nor in LUKS.
|
||||
Some distributions could add these scripts to distributed package, please check your distro updates for more info.
|
||||
|
||||
|
||||
[Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
|
||||
--------------------------------
|
||||
|
||||
@@ -45,37 +44,31 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**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)
|
||||
**The latest cryptsetup version is 2.2.2**
|
||||
* [cryptsetup-2.2.2.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.tar.xz)
|
||||
* Signature [cryptsetup-2.2.2.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.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.2.2 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.2-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.2.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.1.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.1.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.0-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).
|
||||
|
||||
@@ -87,4 +80,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.
|
||||
|
||||
17
autogen.sh
17
autogen.sh
@@ -56,13 +56,6 @@ if test "$DIE" -eq 1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$*"; then
|
||||
echo
|
||||
echo "**Warning**: I am going to run 'configure' with no arguments."
|
||||
echo "If you wish to pass any to it, please specify them on the"
|
||||
echo \'$0\'" command line."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Generate build-system by:"
|
||||
echo " autopoint: $(autopoint --version | head -1)"
|
||||
@@ -81,10 +74,6 @@ autoheader $AH_OPTS
|
||||
automake --add-missing --copy --gnu $AM_OPTS
|
||||
autoconf $AC_OPTS
|
||||
|
||||
if test x$NOCONFIGURE = x; then
|
||||
echo Running $srcdir/configure $conf_flags "$@" ...
|
||||
$srcdir/configure $conf_flags "$@" \
|
||||
&& echo Now type \`make\' to compile $PKG_NAME
|
||||
else
|
||||
echo Skipping configure process.
|
||||
fi
|
||||
echo
|
||||
echo "Now type '$srcdir/configure' and 'make' to compile."
|
||||
echo
|
||||
|
||||
352
configure.ac
352
configure.ac
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.0.0-rc0])
|
||||
AC_INIT([cryptsetup],[2.3.0-rc0])
|
||||
|
||||
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)
|
||||
@@ -15,8 +15,8 @@ AC_CONFIG_HEADERS([config.h:config.h.in])
|
||||
# http://lists.gnu.org/archive/html/automake/2013-01/msg00060.html
|
||||
|
||||
# For old automake use this
|
||||
#AM_INIT_AUTOMAKE(dist-xz)
|
||||
AM_INIT_AUTOMAKE([dist-xz 1.12 serial-tests])
|
||||
#AM_INIT_AUTOMAKE(dist-xz subdir-objects)
|
||||
AM_INIT_AUTOMAKE([dist-xz 1.12 serial-tests subdir-objects])
|
||||
|
||||
if test "x$prefix" = "xNONE"; then
|
||||
sysconfdir=/etc
|
||||
@@ -34,6 +34,25 @@ AC_ENABLE_STATIC(no)
|
||||
LT_INIT
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl define PKG_CHECK_VAR for old pkg-config <= 0.28
|
||||
m4_ifndef([AS_VAR_COPY],
|
||||
[m4_define([AS_VAR_COPY],
|
||||
[AS_LITERAL_IF([$1[]$2], [$1=$$2], [eval $1=\$$2])])
|
||||
])
|
||||
m4_ifndef([PKG_CHECK_VAR], [
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])
|
||||
|
||||
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])
|
||||
])
|
||||
])
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_C_RESTRICT
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
@@ -44,7 +63,9 @@ AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
|
||||
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.])])
|
||||
|
||||
@@ -65,7 +86,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.])])
|
||||
@@ -73,9 +94,9 @@ AC_SUBST(UUID_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
|
||||
AC_CHECK_FUNCS([posix_memalign clock_gettime])
|
||||
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
|
||||
|
||||
@@ -90,7 +111,7 @@ AC_FUNC_STRERROR_R
|
||||
dnl ==========================================================================
|
||||
|
||||
AM_GNU_GETTEXT([external],[need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION([0.15])
|
||||
AM_GNU_GETTEXT_VERSION([0.18.3])
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
@@ -101,12 +122,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
|
||||
@@ -115,7 +134,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
|
||||
])
|
||||
@@ -123,12 +142,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.]))
|
||||
@@ -140,13 +156,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
|
||||
@@ -158,7 +172,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
|
||||
|
||||
@@ -166,20 +180,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
|
||||
@@ -189,7 +209,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,,
|
||||
@@ -213,18 +235,17 @@ 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])
|
||||
CRYPTO_STATIC_LIBS=$OPENSSL_STATIC_LIBS
|
||||
PKG_CONFIG=$saved_PKG_CONFIG
|
||||
fi
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
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
|
||||
|
||||
@@ -257,6 +278,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,,
|
||||
@@ -273,38 +295,42 @@ dnl ==========================================================================
|
||||
saved_LIBS=$LIBS
|
||||
|
||||
AC_ARG_ENABLE([static-cryptsetup],
|
||||
AS_HELP_STRING([--enable-static-cryptsetup],
|
||||
[enable build of static cryptsetup binary]))
|
||||
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(veritysetup,
|
||||
AS_HELP_STRING([--disable-veritysetup],
|
||||
[disable veritysetup support]),[], [enable_veritysetup=yes])
|
||||
AM_CONDITIONAL(VERITYSETUP, test x$enable_veritysetup = 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([cryptsetup-reencrypt],
|
||||
AS_HELP_STRING([--enable-cryptsetup-reencrypt],
|
||||
[enable cryptsetup-reencrypt tool]))
|
||||
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],, [
|
||||
@@ -320,6 +346,9 @@ LIBS="$LIBS $DEVMAPPER_LIBS"
|
||||
AC_CHECK_DECLS([dm_task_secure_data], [], [], [#include <libdevmapper.h>])
|
||||
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_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
|
||||
@@ -332,20 +361,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])
|
||||
@@ -359,24 +388,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])
|
||||
|
||||
AC_ARG_ENABLE(argon2, AS_HELP_STRING([--disable-argon2],
|
||||
[disable internal implementation of Argon2 PBKDF]),[], [enable_argon2=yes])
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test x$enable_argon2 = xyes)
|
||||
if test x$enable_argon2 = xyes ; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
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([libargon2],
|
||||
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
|
||||
|
||||
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
|
||||
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_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"
|
||||
|
||||
@@ -388,7 +481,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"
|
||||
@@ -407,6 +500,10 @@ if test x$enable_static_cryptsetup = xyes; then
|
||||
PKG_CONFIG=$saved_PKG_CONFIG
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for systemd tmpfiles config directory])
|
||||
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
|
||||
AC_MSG_RESULT([$systemd_tmpfilesdir])
|
||||
|
||||
AC_SUBST([DEVMAPPER_LIBS])
|
||||
AC_SUBST([DEVMAPPER_STATIC_LIBS])
|
||||
|
||||
@@ -420,14 +517,20 @@ AC_SUBST([CRYPTO_LIBS])
|
||||
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 ==========================================================================
|
||||
@@ -447,35 +550,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])
|
||||
@@ -488,12 +568,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])
|
||||
|
||||
@@ -506,9 +596,18 @@ CS_NUM_WITH([verity-hash-block], [hash block size for verity mode], [4096])
|
||||
CS_NUM_WITH([verity-salt-size], [salt size for verity mode], [32])
|
||||
CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
|
||||
|
||||
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([tmpfilesdir], [override default path to directory with systemd temporary files], [])
|
||||
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
|
||||
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/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)
|
||||
|
||||
@@ -517,25 +616,24 @@ 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
|
||||
lib/Makefile
|
||||
lib/libcryptsetup.pc
|
||||
lib/crypto_backend/Makefile
|
||||
lib/crypto_backend/argon2/Makefile
|
||||
lib/luks1/Makefile
|
||||
lib/luks2/Makefile
|
||||
lib/loopaes/Makefile
|
||||
lib/verity/Makefile
|
||||
lib/tcrypt/Makefile
|
||||
lib/integrity/Makefile
|
||||
src/Makefile
|
||||
po/Makefile.in
|
||||
man/Makefile
|
||||
scripts/cryptsetup.conf
|
||||
tests/Makefile
|
||||
python/Makefile
|
||||
scripts/Makefile
|
||||
scripts/cryptsetup_tmpfiles.conf
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -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 RC0 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,15 +12,63 @@ 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 API calls or LUKS2 format
|
||||
could still 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.
|
||||
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Enable to use system libargon2 instead of bundled version.
|
||||
Renames --disable-argon2 to --disable-internal-argon2 option
|
||||
and adds --enable-libargon2 flag to allow system libargon2.
|
||||
|
||||
* Changes in build system (Automake)
|
||||
- The build system now uses non-recursive automake (except for tests).
|
||||
(Tools binaries are now located in buildroot directory.)
|
||||
- New --disable-cryptsetup option to disable build of cryptsetup tool.
|
||||
- Enable build of cryptsetup-reencrypt by default.
|
||||
|
||||
* Install tmpfiles.d configuration for LUKS2 locking directory.
|
||||
You can overwrite this using --with-tmpfilesdir configure option.
|
||||
If your distro does not support tmpfiles.d directory, you have
|
||||
to create locking directory (/run/lock/cryptsetup) in cryptsetup
|
||||
package (or init scripts).
|
||||
|
||||
* Adds limited support for offline reencryption of LUKS2 format.
|
||||
|
||||
* Decrease size of testing images (and the whole release archive).
|
||||
|
||||
* Fixes for several memory leaks found by Valgrind and Coverity tools.
|
||||
|
||||
* Fixes for several typos in man pages and error messages.
|
||||
|
||||
* LUKS header file in luksFormat is now automatically created
|
||||
if it does not exist.
|
||||
|
||||
* Do not allow resize if device size is not aligned to sector size.
|
||||
|
||||
Cryptsetup 2.0.0 RC0 Release Notes
|
||||
==================================
|
||||
|
||||
Important features
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
@@ -122,7 +170,7 @@ and for block device by using a specific lock file in /run/lock/cryptsetup.
|
||||
|
||||
This directory must be created by distribution (do not rely on internal
|
||||
fallback). For systemd-based distribution, you can simply install
|
||||
scripts/cryptsetup_tmpfiles.conf into tmpfiles.d directory.
|
||||
scripts/cryptsetup.conf into tmpfiles.d directory.
|
||||
|
||||
For more details see LUKS2-format.txt and LUKS2-locking.txt in the docs
|
||||
directory. (Please note this is just overview, there will be more formal
|
||||
@@ -210,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.
|
||||
@@ -229,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
|
||||
@@ -258,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.
|
||||
@@ -443,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
|
||||
|
||||
@@ -527,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.
|
||||
|
||||
@@ -550,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.
|
||||
206
docs/v2.3.0-rc0-ReleaseNotes
Normal file
206
docs/v2.3.0-rc0-ReleaseNotes
Normal file
@@ -0,0 +1,206 @@
|
||||
Cryptsetup 2.3.0-RC0 Release Notes
|
||||
==================================
|
||||
Testing release with new and 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 BitLocker Full Disk Encryption devices.
|
||||
|
||||
The BITLK implementation is based on publicly available information
|
||||
and is an independent and opensource implementation of this proprietary
|
||||
format.
|
||||
|
||||
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 approaches we used for comparison
|
||||
of 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).
|
||||
|
||||
Activation is supported for AES-XTS encryption 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 will be required (patch for dm-crypt is already available).
|
||||
|
||||
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.
|
||||
|
||||
Libcryptsetup API extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
THe libcryptsetup is backward compatible for other 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
|
||||
@@ -1,82 +0,0 @@
|
||||
SUBDIRS = crypto_backend luks1 luks2 loopaes verity tcrypt integrity
|
||||
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libcryptsetup.pc
|
||||
|
||||
AM_CPPFLAGS = -include config.h \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/lib/crypto_backend \
|
||||
-I$(top_srcdir)/lib/luks1 \
|
||||
-I$(top_srcdir)/lib/luks2 \
|
||||
-I$(top_srcdir)/lib/loopaes \
|
||||
-I$(top_srcdir)/lib/verity \
|
||||
-I$(top_srcdir)/lib/tcrypt \
|
||||
-I$(top_srcdir)/lib/integrity \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DSYSCONFDIR=\""$(sysconfdir)"\" \
|
||||
-DVERSION=\""$(VERSION)"\"
|
||||
|
||||
lib_LTLIBRARIES = libcryptsetup.la
|
||||
|
||||
common_ldadd = \
|
||||
crypto_backend/libcrypto_backend.la \
|
||||
luks1/libluks1.la \
|
||||
luks2/libluks2.la \
|
||||
loopaes/libloopaes.la \
|
||||
verity/libverity.la \
|
||||
tcrypt/libtcrypt.la \
|
||||
integrity/libintegrity.la
|
||||
|
||||
libcryptsetup_la_DEPENDENCIES = $(common_ldadd) libcryptsetup.sym
|
||||
|
||||
libcryptsetup_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
|
||||
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
|
||||
-version-info @LIBCRYPTSETUP_VERSION_INFO@
|
||||
|
||||
libcryptsetup_la_CFLAGS = -Wall $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libcryptsetup_la_LIBADD = \
|
||||
@UUID_LIBS@ \
|
||||
@DEVMAPPER_LIBS@ \
|
||||
@CRYPTO_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
$(common_ldadd)
|
||||
|
||||
|
||||
libcryptsetup_la_SOURCES = \
|
||||
setup.c \
|
||||
internal.h \
|
||||
bitops.h \
|
||||
nls.h \
|
||||
libcryptsetup.h \
|
||||
utils.c \
|
||||
utils_benchmark.c \
|
||||
utils_crypt.c \
|
||||
utils_crypt.h \
|
||||
utils_loop.c \
|
||||
utils_loop.h \
|
||||
utils_devpath.c \
|
||||
utils_wipe.c \
|
||||
utils_fips.c \
|
||||
utils_fips.h \
|
||||
utils_device.c \
|
||||
utils_keyring.c \
|
||||
utils_keyring.h \
|
||||
utils_device_locking.c \
|
||||
utils_device_locking.h \
|
||||
utils_pbkdf.c \
|
||||
libdevmapper.c \
|
||||
utils_dm.h \
|
||||
volumekey.c \
|
||||
random.c \
|
||||
crypt_plain.c \
|
||||
base64.h \
|
||||
base64.c
|
||||
|
||||
include_HEADERS = libcryptsetup.h
|
||||
|
||||
EXTRA_DIST = libcryptsetup.pc.in libcryptsetup.sym
|
||||
114
lib/Makemodule.am
Normal file
114
lib/Makemodule.am
Normal file
@@ -0,0 +1,114 @@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
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 \
|
||||
-I $(top_srcdir)/lib/luks2 \
|
||||
-I $(top_srcdir)/lib/loopaes \
|
||||
-I $(top_srcdir)/lib/verity \
|
||||
-I $(top_srcdir)/lib/tcrypt \
|
||||
-I $(top_srcdir)/lib/integrity \
|
||||
-I $(top_srcdir)/lib/bitlk
|
||||
|
||||
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 \
|
||||
-version-info @LIBCRYPTSETUP_VERSION_INFO@
|
||||
|
||||
libcryptsetup_la_CFLAGS = $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libcryptsetup_la_LIBADD = \
|
||||
@UUID_LIBS@ \
|
||||
@DEVMAPPER_LIBS@ \
|
||||
@CRYPTO_LIBS@ \
|
||||
@LIBARGON2_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
@BLKID_LIBS@ \
|
||||
libcrypto_backend.la \
|
||||
libutils_io.la
|
||||
|
||||
libcryptsetup_la_SOURCES = \
|
||||
lib/setup.c \
|
||||
lib/internal.h \
|
||||
lib/bitops.h \
|
||||
lib/nls.h \
|
||||
lib/libcryptsetup.h \
|
||||
lib/utils.c \
|
||||
lib/utils_benchmark.c \
|
||||
lib/utils_crypt.c \
|
||||
lib/utils_crypt.h \
|
||||
lib/utils_loop.c \
|
||||
lib/utils_loop.h \
|
||||
lib/utils_devpath.c \
|
||||
lib/utils_wipe.c \
|
||||
lib/utils_fips.c \
|
||||
lib/utils_fips.h \
|
||||
lib/utils_device.c \
|
||||
lib/utils_keyring.c \
|
||||
lib/utils_keyring.h \
|
||||
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 \
|
||||
lib/random.c \
|
||||
lib/crypt_plain.c \
|
||||
lib/base64.h \
|
||||
lib/base64.c \
|
||||
lib/integrity/integrity.h \
|
||||
lib/integrity/integrity.c \
|
||||
lib/loopaes/loopaes.h \
|
||||
lib/loopaes/loopaes.c \
|
||||
lib/tcrypt/tcrypt.h \
|
||||
lib/tcrypt/tcrypt.c \
|
||||
lib/luks1/af.h \
|
||||
lib/luks1/af.c \
|
||||
lib/luks1/keyencryption.c \
|
||||
lib/luks1/keymanage.c \
|
||||
lib/luks1/luks.h \
|
||||
lib/verity/verity_hash.c \
|
||||
lib/verity/verity_fec.c \
|
||||
lib/verity/verity.c \
|
||||
lib/verity/verity.h \
|
||||
lib/verity/rs_encode_char.c \
|
||||
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 \
|
||||
lib/luks2/luks2_luks1_convert.c \
|
||||
lib/luks2/luks2_digest.c \
|
||||
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/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
|
||||
|
||||
1144
lib/bitlk/bitlk.c
Normal file
1144
lib/bitlk/bitlk.c
Normal file
File diff suppressed because it is too large
Load Diff
122
lib/bitlk/bitlk.h
Normal file
122
lib/bitlk/bitlk.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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_VMK_OPEN_KEY "openkey"
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libcrypto_backend.la
|
||||
|
||||
libcrypto_backend_la_CFLAGS = $(AM_CFLAGS) -Wall @CRYPTO_CFLAGS@
|
||||
|
||||
libcrypto_backend_la_SOURCES = crypto_backend.h \
|
||||
crypto_cipher_kernel.c crypto_storage.c pbkdf_check.c crc32.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += crypto_gcrypt.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_OPENSSL
|
||||
libcrypto_backend_la_SOURCES += crypto_openssl.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_NSS
|
||||
libcrypto_backend_la_SOURCES += crypto_nss.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_KERNEL
|
||||
libcrypto_backend_la_SOURCES += crypto_kernel.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_NETTLE
|
||||
libcrypto_backend_la_SOURCES += crypto_nettle.c
|
||||
endif
|
||||
|
||||
if CRYPTO_INTERNAL_PBKDF2
|
||||
libcrypto_backend_la_SOURCES += pbkdf2_generic.c
|
||||
endif
|
||||
|
||||
if CRYPTO_INTERNAL_ARGON2
|
||||
SUBDIRS = argon2
|
||||
libcrypto_backend_la_DEPENDENCIES = argon2/libargon2.la
|
||||
libcrypto_backend_la_LIBADD = argon2/libargon2.la
|
||||
libcrypto_backend_la_SOURCES += argon2_generic.c
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -include config.h -I$(top_srcdir)/lib
|
||||
39
lib/crypto_backend/Makemodule.am
Normal file
39
lib/crypto_backend/Makemodule.am
Normal file
@@ -0,0 +1,39 @@
|
||||
noinst_LTLIBRARIES += libcrypto_backend.la
|
||||
|
||||
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/cipher_generic.c \
|
||||
lib/crypto_backend/cipher_check.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_OPENSSL
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_openssl.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_NSS
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_nss.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_KERNEL
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_kernel.c
|
||||
endif
|
||||
if CRYPTO_BACKEND_NETTLE
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_nettle.c
|
||||
endif
|
||||
|
||||
if CRYPTO_INTERNAL_PBKDF2
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/pbkdf2_generic.c
|
||||
endif
|
||||
|
||||
if CRYPTO_INTERNAL_ARGON2
|
||||
libcrypto_backend_la_DEPENDENCIES = libargon2.la
|
||||
libcrypto_backend_la_LIBADD = libargon2.la
|
||||
endif
|
||||
@@ -1,13 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libargon2.la
|
||||
|
||||
libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3 -Wall
|
||||
|
||||
libargon2_la_SOURCES = \
|
||||
blake2/blake2b.c blake2/blake2.h blake2/blake2-impl.h blake2/blamka-round-ref.h \
|
||||
argon2.c argon2.h core.c core.h encoding.c encoding.h ref.c thread.c thread.h
|
||||
|
||||
AM_CPPFLAGS = -Iblake2
|
||||
|
||||
EXTRA_DIST = LICENSE
|
||||
30
lib/crypto_backend/argon2/Makemodule.am
Normal file
30
lib/crypto_backend/argon2/Makemodule.am
Normal file
@@ -0,0 +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 \
|
||||
-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/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/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,8 +20,12 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
#if HAVE_ARGON2_H
|
||||
#include <argon2.h>
|
||||
#else
|
||||
#include "argon2/argon2.h"
|
||||
#endif
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
@@ -30,6 +34,9 @@ int argon2(const char *type, const char *password, size_t password_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
#if !USE_INTERNAL_ARGON2 && !HAVE_ARGON2_H
|
||||
return -EINVAL;
|
||||
#else
|
||||
argon2_type atype;
|
||||
argon2_context context = {
|
||||
.flags = ARGON2_DEFAULT_FLAGS,
|
||||
@@ -68,118 +75,5 @@ int argon2(const char *type, const char *password, size_t password_length,
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
157
lib/crypto_backend/cipher_check.c
Normal file
157
lib/crypto_backend/cipher_check.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
83
lib/crypto_backend/cipher_generic.c
Normal file
83
lib/crypto_backend/cipher_generic.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 },
|
||||
{ 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);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
|
||||
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,6 +22,8 @@
|
||||
#define _CRYPTO_BACKEND_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
struct crypt_device;
|
||||
@@ -43,21 +45,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,54 +81,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
|
||||
|
||||
#if USE_INTERNAL_ARGON2
|
||||
/* internal Argon2 implementation */
|
||||
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);
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
@@ -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 */
|
||||
@@ -363,10 +369,153 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
if (!strcmp(kdf, "pbkdf2"))
|
||||
return pbkdf2(hash, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations);
|
||||
#if USE_INTERNAL_ARGON2
|
||||
else if (!strncmp(kdf, "argon2", 6))
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
@@ -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 */
|
||||
@@ -328,12 +339,65 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
|
||||
iterations, key_length, key, ha->block_length);
|
||||
#if USE_INTERNAL_ARGON2
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -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,18 +374,71 @@ 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);
|
||||
return 0;
|
||||
#if USE_INTERNAL_ARGON2
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -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 */
|
||||
@@ -326,12 +328,65 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
|
||||
iterations, key_length, key, ha->block_length);
|
||||
#if USE_INTERNAL_ARGON2
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -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,20 +303,16 @@ 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 */
|
||||
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
|
||||
{
|
||||
if (fips)
|
||||
return -EINVAL;
|
||||
|
||||
if (RAND_bytes((unsigned char *)buffer, length) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -327,16 +338,209 @@ 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;
|
||||
#if USE_INTERNAL_ARGON2
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
@@ -34,6 +34,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 +151,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 +202,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 +210,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 +218,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 +392,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 +400,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 +422,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,13 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libintegrity.la
|
||||
|
||||
libintegrity_la_CFLAGS = -Wall $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libintegrity_la_SOURCES = \
|
||||
integrity.c \
|
||||
integrity.h
|
||||
|
||||
AM_CPPFLAGS = -include config.h \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/lib/crypto_backend
|
||||
@@ -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
|
||||
@@ -34,15 +34,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 +49,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 +87,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 +120,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 +142,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 +180,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 +192,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 +207,93 @@ 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)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dmd)
|
||||
return -EINVAL;
|
||||
|
||||
*dmd = (struct crypt_dm_active_device) {
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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 +305,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 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);
|
||||
|
||||
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
|
||||
|
||||
134
lib/internal.h
134
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,76 @@
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.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)
|
||||
|
||||
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,36 +107,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(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);
|
||||
@@ -123,6 +159,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);
|
||||
@@ -137,23 +180,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)
|
||||
@@ -170,7 +206,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);
|
||||
@@ -181,6 +217,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,
|
||||
@@ -198,5 +239,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:
|
||||
*;
|
||||
};
|
||||
|
||||
1811
lib/libdevmapper.c
1811
lib/libdevmapper.c
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libloopaes.la
|
||||
|
||||
libloopaes_la_CFLAGS = -Wall $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libloopaes_la_SOURCES = \
|
||||
loopaes.c \
|
||||
loopaes.h
|
||||
|
||||
AM_CPPFLAGS = -include config.h \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/lib/crypto_backend
|
||||
|
||||
@@ -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
|
||||
@@ -87,12 +87,12 @@ static int hash_keys(struct crypt_device *cd,
|
||||
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,17 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libluks1.la
|
||||
|
||||
libluks1_la_CFLAGS = -Wall $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libluks1_la_SOURCES = \
|
||||
af.c \
|
||||
keymanage.c \
|
||||
keyencryption.c \
|
||||
af.h \
|
||||
luks.h
|
||||
|
||||
AM_CPPFLAGS = -include config.h \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/lib/crypto_backend
|
||||
|
||||
@@ -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,10 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "luks.h"
|
||||
#include "af.h"
|
||||
#include "internal.h"
|
||||
@@ -30,17 +32,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 +58,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 +86,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 +145,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 +171,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 +182,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 +212,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 +236,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,23 +0,0 @@
|
||||
moduledir = $(libdir)/cryptsetup
|
||||
|
||||
noinst_LTLIBRARIES = libluks2.la
|
||||
|
||||
libluks2_la_CFLAGS = -Wall $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libluks2_la_SOURCES = \
|
||||
luks2_disk_metadata.c \
|
||||
luks2_json_format.c \
|
||||
luks2_json_metadata.c \
|
||||
luks2_luks1_convert.c \
|
||||
luks2_digest.c \
|
||||
luks2_digest_pbkdf2.c \
|
||||
luks2_keyslot.c \
|
||||
luks2_keyslot_luks2.c \
|
||||
luks2_token_keyring.c \
|
||||
luks2_token.c \
|
||||
luks2_internal.h \
|
||||
luks2.h
|
||||
|
||||
AM_CPPFLAGS = -include config.h \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/lib/crypto_backend
|
||||
@@ -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,14 +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 */
|
||||
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd);
|
||||
#define LUKS2_HDR_OFFSET_MAX 0x400000 /* 4 MiB */
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
/* 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_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,
|
||||
@@ -125,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,
|
||||
@@ -136,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
|
||||
@@ -147,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,
|
||||
@@ -187,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,
|
||||
@@ -223,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,
|
||||
@@ -274,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,
|
||||
@@ -292,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,
|
||||
@@ -307,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
|
||||
*/
|
||||
@@ -335,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,
|
||||
@@ -350,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,60 +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)
|
||||
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) {
|
||||
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;
|
||||
@@ -368,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;
|
||||
@@ -376,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));
|
||||
r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -393,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);
|
||||
@@ -514,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;
|
||||
@@ -549,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;
|
||||
@@ -559,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;
|
||||
@@ -589,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);
|
||||
r = device_check_size(cd, device, hdr_size, 0);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
@@ -597,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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,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);
|
||||
@@ -666,14 +766,19 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd)
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
|
||||
{
|
||||
struct {
|
||||
char magic[LUKS2_MAGIC_L];
|
||||
uint16_t version;
|
||||
} __attribute__ ((packed)) hdr;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
int r, devfd, flags;
|
||||
struct device *device = NULL;
|
||||
int r = 0, devfd = -1, flags;
|
||||
|
||||
if (!backup_file)
|
||||
device = crypt_metadata_device(cd);
|
||||
else if (device_alloc(cd, &device, backup_file) < 0)
|
||||
return 0;
|
||||
|
||||
if (!device)
|
||||
return 0;
|
||||
@@ -684,16 +789,18 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd)
|
||||
|
||||
devfd = open(device_path(device), flags);
|
||||
if (devfd < 0)
|
||||
return 0;
|
||||
goto err;
|
||||
|
||||
if ((read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), &hdr, sizeof(hdr), 0)
|
||||
!= sizeof(hdr)) ||
|
||||
memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
|
||||
r = 0;
|
||||
else
|
||||
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);
|
||||
err:
|
||||
if (devfd != -1)
|
||||
close(devfd);
|
||||
|
||||
if (backup_file)
|
||||
device_free(cd, device);
|
||||
|
||||
close(devfd);
|
||||
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
|
||||
@@ -33,41 +33,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);
|
||||
json_object *json_object_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 +104,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 +116,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 +163,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 +180,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", json_object_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
|
||||
json_object_object_add(jobj_config, "keyslots_size", json_object_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", json_object_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 = json_object_get_uint64(jobj);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
|
||||
return -EINVAL;
|
||||
*length = json_object_get_int64(jobj);
|
||||
*length = json_object_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", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_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,6 +212,12 @@ 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);
|
||||
@@ -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))
|
||||
@@ -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", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_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", json_object_get_uint32(jobj1) * 8);
|
||||
|
||||
json_object_object_get_ex(jobj_kdf, "type", &jobj1);
|
||||
log_std(cd, "\tPBKDF: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
@@ -579,7 +620,7 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_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,6 +636,9 @@ 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));
|
||||
|
||||
@@ -604,59 +648,47 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
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", json_object_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", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_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 = json_object_get_uint64(jobj_offset);
|
||||
area_length = json_object_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:", json_object_get_uint64(jobj1));
|
||||
}
|
||||
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj1);
|
||||
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", json_object_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));
|
||||
|
||||
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 = json_object_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 = json_object_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", json_object_new_uint64(offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_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 = json_object_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,8 @@ 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", json_object_new_uint64(json_size));
|
||||
json_object_object_add(field, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
|
||||
*luks1_object = luks1_obj;
|
||||
return 0;
|
||||
@@ -410,7 +410,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;
|
||||
|
||||
@@ -420,7 +419,7 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
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)));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,86 +427,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;
|
||||
@@ -543,22 +586,26 @@ 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)
|
||||
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 +619,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 +632,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 +649,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 +660,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 +678,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;
|
||||
}
|
||||
}
|
||||
@@ -674,8 +753,12 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -770,7 +853,8 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
/* 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 +868,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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user