kcapi/akcipher.rs
1/*
2 * $Id$
3 *
4 * Copyright (c) 2021, Purushottam A. Kulkarni.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation and
15 * or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its contributors
18 * may be used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE
32 *
33 */
34
35//!
36//! # Asymmetric Key Ciphers (akcipher) using the Kernel Crypto API
37//!
38//! This module is **EXPERIMENTAL**
39//!
40//! This module provides the capability to perform asymmetric key encryption,
41//! decryption, signing, and verification using the KCAPI provided the following
42//! conditions are met:
43//!
44//! 1. The patches in the `kernel-patches` directory are successfully applied.
45//! 2. The kernel is compiled with `CONFIG_CRYPTO_USER_API_AKCIPHER=y`
46//!
47//! *Note:* Any asymmetric key cipher used with this module **MUST** be present
48//! in `/proc/crypto` on the target device.
49//!
50//! # Layout
51//!
52//! This module provides one-shot convenience functions to perform encryption,
53//! decryption, signing, and verification using any AK cipher present in
54//! `/proc/crypto`. This module also provides the `KcapiAKCipher` type which
55//! provides APIs to initialize, set public and private keys, encrypt, decrypt,
56//! sign, and verify using the appropriate algorithm from `/proc/crypto`.
57//!
58//!
59//! ## Caveats
60//!
61//! Since the support to perform asymmetric cipher operations from userland is
62//! not present in the upstream Linux kernel, this module is still **EXPERIMENTAL**.
63//! This module is **only** available when the `asym` feature is enabled.
64//! This is because the `akcipher_*` APIs are available only when `libkcapi` is configured
65//! to have them.
66//!
67//! **WARNING**: Prior to using this API with the `local-kcapi` feature enabled,
68//! ensure that you have `lib-asym` configured for your `libkcapi` installation.
69//!
70
71use std::{convert::TryInto, ffi::CString};
72
73use crate::{KcapiError, KcapiResult, VMSplice, ACCESS_HEURISTIC, INIT_AIO};
74
75///
76/// # The `KcapiAKCipher` Type
77///
78/// This type denotes a generic context for an Asymmetric Key cipher transform
79/// in the Linux Kernel. An instance of this struct must be initialized using
80/// the `new()` call prior to being used. This type provides APIs to perform:
81///
82/// * setting of public and private keys.
83/// * encryption
84/// * decryption
85/// * signing
86/// * verification
87///
88/// ## Panics
89///
90/// If the string provided as input to the `new()` function cannot be converted into a
91/// `std::ffi::CString` type, the initialization will panic with the message
92/// `Failed to create CString`.
93///
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct KcapiAKCipher {
96 handle: *mut kcapi_sys::kcapi_handle,
97 pubkey: Vec<u8>,
98 privkey: Vec<u8>,
99 pub modsize: usize,
100 pub algorithm: String,
101}
102
103impl KcapiAKCipher {
104 ///
105 /// ## Initialize an instance of the `KcapiAKCipher` Type.
106 ///
107 /// This function initializes an instance of the `KcapiAKCipher` Type and
108 /// makes the necessary connections to the kernel through `kcapi-sys`.
109 ///
110 /// This function takes:
111 /// * `algorithm` - a `&str` representation of an `akcipher` algorithm in `/proc/crypto`
112 /// * `flags` - `u32` flags specifying the type of cipher handle.
113 ///
114 /// On success, an initialized instance of `KcapiAKCipher` is returned.
115 /// On failure, a `KcapiError` is returned.
116 ///
117 pub fn new(algorithm: &str, flags: u32) -> KcapiResult<Self> {
118 let mut handle = Box::into_raw(Box::new(crate::kcapi_handle { _unused: [0u8; 0] }))
119 as *mut kcapi_sys::kcapi_handle;
120 let pubkey = Vec::<u8>::new();
121 let privkey = Vec::<u8>::new();
122
123 let alg = CString::new(algorithm).expect("Failed to create CString");
124 unsafe {
125 let ret = kcapi_sys::kcapi_akcipher_init(&mut handle as *mut _, alg.as_ptr(), flags);
126 if ret < 0 {
127 return Err(KcapiError {
128 code: ret,
129 message: format!(
130 "Failed to initialize akcipher handle for algorithm '{}'",
131 algorithm
132 ),
133 });
134 }
135 }
136
137 Ok(KcapiAKCipher {
138 algorithm: algorithm.to_string(),
139 handle,
140 modsize: 0,
141 pubkey,
142 privkey,
143 })
144 }
145
146 ///
147 /// ## Set the Private Key
148 ///
149 /// This function is used to set the private key for decryption and
150 /// signing operations.
151 ///
152 /// The key must be a `Vec<u8>` in DER format as follows:
153 ///
154 /// ```none
155 /// SEQUENCE {
156 /// version INTEGER,
157 /// n INTEGER ({ rsa_get_n }),
158 /// e INTEGER ({ rsa_get_e }),
159 /// d INTEGER ({ rsa_get_d }),
160 /// prime1 INTEGER,
161 /// prime2 INTEGER,
162 /// exponent1 INTEGER,
163 /// exponent2 INTEGER,
164 /// coefficient INTEGER
165 /// }
166 /// ```
167 ///
168 /// This function takes:
169 /// * `privkey` - A `Vec<u8>` containing the key in the above format.
170 ///
171 /// On failure, a `KcapiError` is returned.
172 pub fn setprivkey(&mut self, privkey: Vec<u8>) -> KcapiResult<()> {
173 unsafe {
174 let ret = kcapi_sys::kcapi_akcipher_setkey(
175 self.handle,
176 privkey.as_ptr(),
177 privkey.len() as u32,
178 );
179
180 if ret < 0 {
181 return Err(KcapiError {
182 code: ret,
183 message: format!(
184 "Failed to set private key for algorithm '{}'",
185 self.algorithm
186 ),
187 });
188 }
189 self.modsize = ret.try_into().expect("Failed to convert i32 into usize");
190 self.privkey = privkey;
191 }
192
193 Ok(())
194 }
195
196 ///
197 /// ## Set the Public Key
198 ///
199 /// This function is used to set the public key for encryption and
200 /// verification operations.
201 ///
202 /// The public key must be a `Vec<u8>` in DER format as follows:
203 ///
204 /// ```none
205 /// SEQUENCE {
206 /// n INTEGER ({ rsa_get_n }),
207 /// e INTEGER ({ rsa_get_e })
208 /// }
209 /// ```
210 ///
211 /// This function takes:
212 /// * `pubkey` - A `Vec<u8>` containing the public key in the above format.
213 ///
214 /// On failure, a `KcapiError` is returned.
215 ///
216 pub fn setpubkey(&mut self, pubkey: Vec<u8>) -> KcapiResult<()> {
217 unsafe {
218 let ret = kcapi_sys::kcapi_akcipher_setpubkey(
219 self.handle,
220 pubkey.as_ptr(),
221 pubkey.len() as u32,
222 );
223 if ret < 0 {
224 return Err(KcapiError {
225 code: ret,
226 message: format!(
227 "Failed to set public key for algorithm '{}'",
228 self.algorithm
229 ),
230 });
231 }
232 self.modsize = ret.try_into().expect("Failed to convert i32 into usize");
233 self.pubkey = pubkey;
234 }
235 Ok(())
236 }
237
238 ///
239 /// ## Perform Asymmetric Encryption
240 ///
241 /// This function encrypts data using a public key. It is necessary to
242 /// set the publickey prior to calling `encrypt()`.
243 ///
244 /// *Note:* Only `self.modsize` bytes of data can be encrypted at a time.
245 ///
246 /// This function takes:
247 /// * `pt` - A `Vec<u8>` containing the plaintext to be encrypted.
248 /// * `access` - kernel access type (`u32`)
249 /// - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
250 /// - `ACCESS_VMSPLICE` - vmsplice access
251 /// - `ACCESS_SENDMSG` - sendmsg access
252 ///
253 /// On success, returns a `Vec<u8>` wih the encrypted ciphertext.
254 /// On failure, returns `KcapiError`
255 ///
256 pub fn encrypt(&self, pt: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
257 crate::akcipher::check_input(self, pt.clone())?;
258
259 let mut ct = vec![0u8; self.modsize];
260 unsafe {
261 let ret = kcapi_sys::kcapi_akcipher_encrypt(
262 self.handle,
263 pt.as_ptr(),
264 pt.len() as kcapi_sys::size_t,
265 ct.as_mut_ptr(),
266 ct.len() as kcapi_sys::size_t,
267 access as i32,
268 );
269 if ret < 0 {
270 return Err(KcapiError {
271 code: ret.try_into().expect("failed to convert i64 into i32"),
272 message: format!("Failed to encrypt for algorithm '{}'", self.algorithm),
273 });
274 }
275 }
276 Ok(ct)
277 }
278
279 ///
280 /// ## Perform Asymmetric Decryption
281 ///
282 /// This function decrypts data using a private key. It is necessary to
283 /// set the privatekey prior to calling `decrypt()`.
284 ///
285 /// *Note:* Only `self.modsize` bytes of data can be decrypted at a time.
286 ///
287 /// This function takes:
288 /// * `pt` - A `Vec<u8>` containing the ciphertext to be decrypted.
289 /// * `access` - kernel access type (`u32`)
290 /// - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
291 /// - `ACCESS_VMSPLICE` - vmsplice access
292 /// - `ACCESS_SENDMSG` - sendmsg access
293 ///
294 /// On success, returns a `Vec<u8>` wih the decrypted plaintext.
295 /// On failure, returns `KcapiError`
296 ///
297 pub fn decrypt(&self, ct: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
298 crate::akcipher::check_input(self, ct.clone())?;
299
300 let mut pt = vec![0u8; self.modsize];
301 unsafe {
302 let ret = kcapi_sys::kcapi_akcipher_decrypt(
303 self.handle,
304 ct.as_ptr(),
305 ct.len() as kcapi_sys::size_t,
306 pt.as_mut_ptr(),
307 pt.len() as kcapi_sys::size_t,
308 access as ::std::os::raw::c_int,
309 );
310 if ret < 0 {
311 return Err(KcapiError {
312 code: ret.try_into().expect("failed to convert i64 into i32"),
313 message: format!("Failed to decrypt for algorithm '{}'", self.algorithm),
314 });
315 }
316 }
317 Ok(pt)
318 }
319
320 ///
321 /// ## Perform Signing
322 ///
323 /// This function signs data using a private key. It is necessary to
324 /// set the privatekey prior to calling `sign()`.
325 ///
326 /// This function takes:
327 /// * `message` - A `Vec<u8>` containing the message to be signed.
328 /// * `access` - kernel access type (`u32`)
329 /// - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
330 /// - `ACCESS_VMSPLICE` - vmsplice access
331 /// - `ACCESS_SENDMSG` - sendmsg access
332 ///
333 /// On success, returns a `Vec<u8>` wih the signature.
334 /// On failure, returns `KcapiError`
335 ///
336 pub fn sign(&self, message: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
337 crate::akcipher::check_input(self, message.clone())?;
338
339 let mut sig = vec![0u8; self.modsize];
340 unsafe {
341 let ret = kcapi_sys::kcapi_akcipher_sign(
342 self.handle,
343 message.as_ptr(),
344 message.len() as kcapi_sys::size_t,
345 sig.as_mut_ptr(),
346 sig.len() as kcapi_sys::size_t,
347 access as ::std::os::raw::c_int,
348 );
349 if ret < 0 {
350 return Err(KcapiError {
351 code: ret.try_into().expect("failed to convert i64 into i32"),
352 message: format!("Failed to sign for algorithm '{}'", self.algorithm),
353 });
354 }
355 }
356 Ok(sig)
357 }
358
359 ///
360 /// ## Perform Signature Verification
361 ///
362 /// This function verifys data using a private key. It is necessary to
363 /// set the privatekey prior to calling `verify()`.
364 ///
365 /// This function takes:
366 /// * `message` - A `Vec<u8>` containing the message to be verified.
367 /// * `sig` - A `Vec<u8>` containing the signature to be verified.
368 /// * `access` - kernel access type (`u32`)
369 /// - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
370 /// - `ACCESS_VMSPLICE` - vmsplice access
371 /// - `ACCESS_SENDMSG` - sendmsg access
372 ///
373 /// On failure to verify the signature, returns `KcapiError` with the `code`
374 /// field set to `EBADMSG`.
375 ///
376 pub fn verify(&self, message: Vec<u8>, sig: Vec<u8>, access: u32) -> KcapiResult<()> {
377 crate::akcipher::check_input(self, sig.clone())?;
378
379 let mut inp = Vec::new();
380 inp.extend(sig.iter().copied());
381 inp.extend(message.iter().copied());
382
383 let mut out = vec![0u8; self.modsize];
384 unsafe {
385 let ret = kcapi_sys::kcapi_akcipher_verify(
386 self.handle,
387 inp.as_ptr(),
388 inp.len() as kcapi_sys::size_t,
389 out.as_mut_ptr(),
390 out.len() as kcapi_sys::size_t,
391 access as ::std::os::raw::c_int,
392 );
393 if ret < 0 {
394 return Err(KcapiError {
395 code: -libc::EBADMSG,
396 message: format!(
397 "Failed to verify signature for algorithm '{}'",
398 self.algorithm
399 ),
400 });
401 }
402 }
403 Ok(())
404 }
405}
406
407impl Drop for KcapiAKCipher {
408 fn drop(&mut self) {
409 unsafe {
410 kcapi_sys::kcapi_akcipher_destroy(self.handle);
411 }
412 }
413}
414
415impl VMSplice for KcapiAKCipher {
416 ///
417 /// ## Get Maximum buffer size of VMSPLICE Access
418 ///
419 /// This function returns the maximum number of bytes that can be handled
420 /// by a VMSPLICE call to the kernel.
421 ///
422 fn get_max_splicesize(&self) -> usize {
423 let size: usize;
424 unsafe {
425 size = kcapi_sys::kcapi_get_maxsplicesize(self.handle) as usize;
426 }
427 size
428 }
429
430 ///
431 /// ## Set Maximum Buffer Size for VMSPLICE Access
432 ///
433 /// When using vmsplice/splice to avoid copying of data into the kernel, the
434 /// kernel enforces a maximum number of bytes which can be spliced. If larger
435 /// data is to be processed, sendmsg will be used.
436 ///
437 /// Using this call, the buffer size can be increased.
438 ///
439 /// *NOTE:* Splice uses a pipe pair. Therefore, the maximum number of bytes
440 /// that can be stored with the pipe governs the maximum data size to be
441 /// spliced. Increasing the pipe buffer size is only allowed up to the maximum
442 /// specified with `/proc/sys/fs/pipe-max-size`.
443 ///
444 /// This function takes:
445 /// `size` - A `usize` denoting the size of the vmsplice buffer.
446 ///
447 /// On failure a `KcapiResult` is returned.
448 ///
449 fn set_max_splicesize(&self, size: usize) -> KcapiResult<()> {
450 unsafe {
451 let ret =
452 kcapi_sys::kcapi_set_maxsplicesize(self.handle, size as ::std::os::raw::c_uint);
453
454 if ret < 0 {
455 return Err(KcapiError {
456 code: ret,
457 message: format!(
458 "Unable to set max splice size {} for algorithm {}",
459 size, self.algorithm,
460 ),
461 });
462 }
463 }
464 Ok(())
465 }
466}
467
468fn check_input(handle: &KcapiAKCipher, inp: Vec<u8>) -> KcapiResult<()> {
469 if handle.privkey.is_empty() && handle.pubkey.is_empty() {
470 return Err(KcapiError {
471 code: -libc::EINVAL,
472 message: format!(
473 "Required asymmetric key is not set for algorithm '{}'",
474 handle.algorithm
475 ),
476 });
477 }
478 if inp.len() > handle.modsize {
479 return Err(KcapiError {
480 code: -libc::EINVAL,
481 message: format!(
482 "Input to asymmetric cipher is larger than modulus size for algorithm {}",
483 handle.algorithm
484 ),
485 });
486 }
487 Ok(())
488}
489
490///
491/// ## Convenience Function to Perform Asymmetric Encryption
492///
493/// This function encrypts data using a public key. The key provided
494/// for the encryption operation should be DER encoded in the following
495/// format:
496///
497/// ```none
498/// SEQUENCE {
499/// n INTEGER ({ rsa_get_n }),
500/// e INTEGER ({ rsa_get_e })
501/// }
502/// ```
503///
504/// *Note:* Only `self.modsize` bytes of data can be encrypted at a time.
505///
506/// This function takes:
507/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
508/// * `key` - A `Vec<u8>` with the public key.
509/// * `pt` - A `Vec<u8>` containing the plaintext to be encrypted.
510///
511/// On success, returns a `Vec<u8>` wih the encrypted ciphertext.
512/// On failure, returns `KcapiError`
513///
514pub fn encrypt(alg: &str, key: Vec<u8>, pt: Vec<u8>) -> KcapiResult<Vec<u8>> {
515 let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
516 handle.setpubkey(key)?;
517 let ct = handle.encrypt(pt, ACCESS_HEURISTIC)?;
518 Ok(ct)
519}
520
521///
522/// ## Convenience Function to Perform Asymmetric Decryption
523///
524/// This function decrypts data using a private key.
525/// The key must be a `Vec<u8>` in DER format as follows:
526///
527/// ```none
528/// SEQUENCE {
529/// version INTEGER,
530/// n INTEGER ({ rsa_get_n }),
531/// e INTEGER ({ rsa_get_e }),
532/// d INTEGER ({ rsa_get_d }),
533/// prime1 INTEGER,
534/// prime2 INTEGER,
535/// exponent1 INTEGER,
536/// exponent2 INTEGER,
537/// coefficient INTEGER
538/// }
539/// ```
540///
541/// *Note:* Only `self.modsize` bytes of data can be decrypted at a time.
542///
543/// This function takes:
544/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
545/// * `key` - A `Vec<u8>` with the private key.
546/// * `ct` - A `Vec<u8>` containing the ciphertext to be decrypted.
547///
548/// On success, returns a `Vec<u8>` wih the decrypted plaintext.
549/// On failure, returns `KcapiError`
550///
551pub fn decrypt(alg: &str, key: Vec<u8>, ct: Vec<u8>) -> KcapiResult<Vec<u8>> {
552 let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
553 handle.setprivkey(key)?;
554 let pt = handle.decrypt(ct, ACCESS_HEURISTIC)?;
555 Ok(pt)
556}
557
558///
559/// ## Convenience Function to Perform Signing
560///
561/// This function signs data using a private key.
562/// The key must be a `Vec<u8>` in DER format as follows:
563///
564/// ```none
565/// SEQUENCE {
566/// version INTEGER,
567/// n INTEGER ({ rsa_get_n }),
568/// e INTEGER ({ rsa_get_e }),
569/// d INTEGER ({ rsa_get_d }),
570/// prime1 INTEGER,
571/// prime2 INTEGER,
572/// exponent1 INTEGER,
573/// exponent2 INTEGER,
574/// coefficient INTEGER
575/// }
576/// ```
577///
578/// This function takes:
579/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
580/// * `key` - A `Vec<u8>` with the private key.
581/// * `message` - A `Vec<u8>` containing the message to be signed.
582///
583/// On success, returns a `Vec<u8>` wih the signature.
584/// On failure, returns `KcapiError`
585///
586pub fn sign(alg: &str, key: Vec<u8>, message: Vec<u8>) -> KcapiResult<Vec<u8>> {
587 let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
588 handle.setprivkey(key)?;
589 let sig = handle.sign(message, ACCESS_HEURISTIC)?;
590 Ok(sig)
591}
592
593///
594/// ## Perform Signature Verification
595///
596/// This function verifys data using a private key. The key provided
597/// for the encryption operation should be DER encoded in the following
598/// format:
599///
600/// ```none
601/// SEQUENCE {
602/// n INTEGER ({ rsa_get_n }),
603/// e INTEGER ({ rsa_get_e })
604/// }
605/// ```
606///
607/// This function takes:
608/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
609/// * `key` - A `Vec<u8>` with the public key.
610/// * `message` - A `Vec<u8>` containing the message to be verified.
611/// * `sig` - A `Vec<u8>` containing the signature to be verified.
612///
613/// On failure to verify the signature, returns `KcapiError` with the `code`
614/// field set to `EBADMSG`.
615///
616pub fn verify(alg: &str, key: Vec<u8>, message: Vec<u8>, sig: Vec<u8>) -> KcapiResult<()> {
617 let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
618 handle.setpubkey(key)?;
619 handle.verify(message, sig, ACCESS_HEURISTIC)?;
620 Ok(())
621}