vendor patches & crates.io compliant metadata
This commit is contained in:
4
patch/cryptsetup-rs/.gitignore
vendored
Normal file
4
patch/cryptsetup-rs/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
target/
|
||||
Cargo.lock
|
||||
*.iml
|
||||
.idea/
|
22
patch/cryptsetup-rs/.travis.yml
Normal file
22
patch/cryptsetup-rs/.travis.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
sudo: required
|
||||
dist: trusty
|
||||
os:
|
||||
- linux
|
||||
script:
|
||||
- cargo build --all-targets --verbose
|
||||
- sudo /bin/sh -c "PATH=/home/travis/.cargo/bin:$PATH LD_LIBRARY_PATH=/home/travis/.cargo/lib cargo test --verbose"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcryptsetup-dev
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
32
patch/cryptsetup-rs/Cargo.toml
Normal file
32
patch/cryptsetup-rs/Cargo.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
authors = ["Vladimir Lushnikov <vladimir@solidninja.is>"]
|
||||
description = "Rust wrapper around the libcryptsetup library, allowing manipulation of LUKS devices in Linux"
|
||||
homepage = "https://github.com/solidninja/cryptsetup-rs"
|
||||
license = "LGPL-3.0"
|
||||
name = "cryptsetup-rs"
|
||||
version = "0.2.0"
|
||||
|
||||
[dependencies]
|
||||
errno = "0.2.3"
|
||||
libc = "0.2.42"
|
||||
log = "0.4.2"
|
||||
|
||||
[dependencies.blkid-rs]
|
||||
path = "blkid-rs"
|
||||
version = "0.1.1"
|
||||
|
||||
[dependencies.libcryptsetup-sys]
|
||||
path = "libcryptsetup-sys"
|
||||
version = "0.1.1"
|
||||
|
||||
[dependencies.uuid]
|
||||
features = ["v4"]
|
||||
version = "0.6.5"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.5.10"
|
||||
expectest = "0.10.0"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
[lib]
|
||||
name = "cryptsetup_rs"
|
165
patch/cryptsetup-rs/LICENSE
Normal file
165
patch/cryptsetup-rs/LICENSE
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
29
patch/cryptsetup-rs/README.md
Normal file
29
patch/cryptsetup-rs/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
[](https://travis-ci.org/solidninja/cryptsetup-rs)
|
||||
[](https://crates.io/crates/cryptsetup-rs)
|
||||
[](https://docs.rs/crate/cryptsetup-rs/)
|
||||
|
||||
# cryptsetup-rs - Rust bindings to `libcryptsetup` on Linux
|
||||
|
||||
A safe binding to `libcryptsetup` that allows working with encrypted disks on Linux.
|
||||
|
||||
Features:
|
||||
* High-level API for open/format/other operations
|
||||
|
||||
|
||||
Documentation for the bindings can be found on [docs.rs](https://docs.rs/crate/cryptsetup-rs/).
|
||||
|
||||
The example [`luks_dump.rs`](examples/luks_dump.rs) shows how a command like `cryptsetup luksDump` can
|
||||
be implemented.
|
||||
|
||||
## TODO
|
||||
|
||||
* Secure string for passing keys
|
||||
* High-level API for non-LUKS1 disks (truecrypt, verity)
|
||||
* LUKS2 and cryptsetup2 support
|
||||
|
||||
## Contributing
|
||||
|
||||
`cryptsetup-rs` is the work of its contributors and is a free software project licensed under the
|
||||
LGPLv3 or later.
|
||||
|
||||
If you would like to contribute, please follow the [C4](https://rfc.zeromq.org/spec:42/C4/) process.
|
2
patch/cryptsetup-rs/blkid-rs/.gitignore
vendored
Normal file
2
patch/cryptsetup-rs/blkid-rs/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target/
|
||||
Cargo.lock
|
18
patch/cryptsetup-rs/blkid-rs/Cargo.toml
Normal file
18
patch/cryptsetup-rs/blkid-rs/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "blkid-rs"
|
||||
version = "0.1.1"
|
||||
authors = ["Vladimir Lushnikov <vladimir@solidninja.is>"]
|
||||
description = "Rust implementation of blkid for LUKS volumes"
|
||||
license = "LGPL-3.0"
|
||||
homepage = "https://github.com/solidninja/libcryptset-rs"
|
||||
|
||||
[lib]
|
||||
name = "blkid_rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.1"
|
||||
uuid = "0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.4"
|
||||
tempdir = "0.3"
|
286
patch/cryptsetup-rs/blkid-rs/src/lib.rs
Normal file
286
patch/cryptsetup-rs/blkid-rs/src/lib.rs
Normal file
@@ -0,0 +1,286 @@
|
||||
// The following code has been ported from libcryptsetup
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate uuid;
|
||||
|
||||
use std::convert;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::str;
|
||||
|
||||
pub trait LuksHeader {
|
||||
fn version(&self) -> u16;
|
||||
fn cipher_name(&self) -> Result<&str, Error>;
|
||||
fn cipher_mode(&self) -> Result<&str, Error>;
|
||||
fn hash_spec(&self) -> Result<&str, Error>;
|
||||
fn payload_offset(&self) -> u32;
|
||||
fn key_bytes(&self) -> u32;
|
||||
fn mk_digest(&self) -> &[u8];
|
||||
fn mk_digest_salt(&self) -> &[u8];
|
||||
fn mk_digest_iterations(&self) -> u32;
|
||||
fn uuid(&self) -> Result<uuid::Uuid, Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
InvalidMagic,
|
||||
InvalidStringEncoding(str::Utf8Error),
|
||||
InvalidVersion,
|
||||
InvalidUuid(uuid::ParseError),
|
||||
ReadError(io::Error),
|
||||
ReadIncorrectHeaderSize,
|
||||
HeaderProcessingError,
|
||||
}
|
||||
|
||||
pub struct BlockDevice;
|
||||
|
||||
impl BlockDevice {
|
||||
pub fn read_luks_header<R: Read>(reader: R) -> Result<raw::luks_phdr, Error> {
|
||||
let luks_phdr_size = mem::size_of::<raw::luks_phdr>();
|
||||
let mut buf = Vec::<u8>::with_capacity(luks_phdr_size);
|
||||
let read_size = try!(reader.take(luks_phdr_size as u64).read_to_end(&mut buf));
|
||||
if read_size != luks_phdr_size {
|
||||
Err(Error::ReadIncorrectHeaderSize)
|
||||
} else {
|
||||
raw::luks_phdr::from_buf(&buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl convert::From<str::Utf8Error> for Error {
|
||||
fn from(error: str::Utf8Error) -> Error {
|
||||
Error::InvalidStringEncoding(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl convert::From<uuid::ParseError> for Error {
|
||||
fn from(error: uuid::ParseError) -> Error {
|
||||
Error::InvalidUuid(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl convert::From<io::Error> for Error {
|
||||
fn from(error: io::Error) -> Error {
|
||||
Error::ReadError(error)
|
||||
}
|
||||
}
|
||||
/* FIXME
|
||||
impl convert::From<byteorder::Error> for Error {
|
||||
fn from(error: byteorder::Error) -> Error {
|
||||
match error {
|
||||
byteorder::Error::UnexpectedEOF => Error::HeaderProcessingError,
|
||||
byteorder::Error::Io(io_error) => Error::ReadError(io_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub mod raw {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::convert::From;
|
||||
use std::io::{Cursor, Read};
|
||||
use std::mem;
|
||||
use std::str;
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use uuid;
|
||||
|
||||
const LUKS_VERSION_SUPPORTED: u16 = 1;
|
||||
|
||||
const LUKS_MAGIC_L: usize = 6;
|
||||
const LUKS_CIPHERNAME_L: usize = 32;
|
||||
const LUKS_CIPHERMODE_L: usize = 32;
|
||||
const LUKS_HASHSPEC_L: usize = 32;
|
||||
const LUKS_DIGESTSIZE: usize = 20;
|
||||
const LUKS_SALTSIZE: usize = 32;
|
||||
const UUID_STRING_L: usize = 40;
|
||||
|
||||
const LUKS_MAGIC: &'static [u8; LUKS_MAGIC_L] = b"LUKS\xba\xbe";
|
||||
|
||||
#[repr(C, packed)]
|
||||
pub struct luks_phdr {
|
||||
pub magic: [u8; LUKS_MAGIC_L],
|
||||
pub version: u16,
|
||||
pub cipherName: [u8; LUKS_CIPHERNAME_L],
|
||||
pub cipherMode: [u8; LUKS_CIPHERMODE_L],
|
||||
pub hashSpec: [u8; LUKS_HASHSPEC_L],
|
||||
pub payloadOffset: u32,
|
||||
pub keyBytes: u32,
|
||||
pub mkDigest: [u8; LUKS_DIGESTSIZE],
|
||||
pub mkDigestSalt: [u8; LUKS_SALTSIZE],
|
||||
pub mkDigestIterations: u32,
|
||||
pub uuid: [u8; UUID_STRING_L],
|
||||
}
|
||||
|
||||
impl luks_phdr {
|
||||
pub fn from_buf(buf: &[u8]) -> Result<luks_phdr, super::Error> {
|
||||
// FIXME - this is not particularly pretty
|
||||
|
||||
if buf.len() != mem::size_of::<luks_phdr>() {
|
||||
return Err(super::Error::ReadIncorrectHeaderSize);
|
||||
}
|
||||
let mut cursor = Cursor::new(buf);
|
||||
let mut magic_buf = [0u8; LUKS_MAGIC_L];
|
||||
let magic_len = try!(cursor.read(&mut magic_buf));
|
||||
|
||||
if magic_len != LUKS_MAGIC_L || magic_buf != &LUKS_MAGIC[..] {
|
||||
return Err(super::Error::InvalidMagic);
|
||||
}
|
||||
|
||||
let version = try!(cursor.read_u16::<BigEndian>());
|
||||
if version != LUKS_VERSION_SUPPORTED {
|
||||
return Err(super::Error::InvalidVersion);
|
||||
}
|
||||
|
||||
let mut cipher_name_buf = [0u8; LUKS_CIPHERNAME_L];
|
||||
let cipher_name_len = try!(cursor.read(&mut cipher_name_buf));
|
||||
if cipher_name_len != LUKS_CIPHERNAME_L {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let mut cipher_mode_buf = [0u8; LUKS_CIPHERMODE_L];
|
||||
let cipher_mode_len = try!(cursor.read(&mut cipher_mode_buf));
|
||||
if cipher_mode_len != LUKS_CIPHERMODE_L {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let mut hash_spec_buf = [0u8; LUKS_HASHSPEC_L];
|
||||
let hash_spec_len = try!(cursor.read(&mut hash_spec_buf));
|
||||
if hash_spec_len != LUKS_HASHSPEC_L {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let payload_offset = try!(cursor.read_u32::<BigEndian>());
|
||||
let key_bytes = try!(cursor.read_u32::<BigEndian>());
|
||||
|
||||
let mut mk_digest_buf = [0u8; LUKS_DIGESTSIZE];
|
||||
let mk_digest_len = try!(cursor.read(&mut mk_digest_buf));
|
||||
if mk_digest_len != LUKS_DIGESTSIZE {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let mut mk_digest_salt_buf = [0u8; LUKS_SALTSIZE];
|
||||
let mk_digest_salt_len = try!(cursor.read(&mut mk_digest_salt_buf));
|
||||
if mk_digest_salt_len != LUKS_SALTSIZE {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let mk_digest_iterations = try!(cursor.read_u32::<BigEndian>());
|
||||
|
||||
let mut uuid_buf = [0u8; UUID_STRING_L];
|
||||
let uuid_len = try!(cursor.read(&mut uuid_buf));
|
||||
if uuid_len != UUID_STRING_L {
|
||||
return Err(super::Error::HeaderProcessingError);
|
||||
}
|
||||
|
||||
let res = luks_phdr {
|
||||
magic: magic_buf,
|
||||
version: version,
|
||||
cipherName: cipher_name_buf,
|
||||
cipherMode: cipher_mode_buf,
|
||||
hashSpec: hash_spec_buf,
|
||||
payloadOffset: payload_offset,
|
||||
keyBytes: key_bytes,
|
||||
mkDigest: mk_digest_buf,
|
||||
mkDigestSalt: mk_digest_salt_buf,
|
||||
mkDigestIterations: mk_digest_iterations,
|
||||
uuid: uuid_buf,
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
fn u8_buf_to_str(buf: &[u8]) -> Result<&str, super::Error> {
|
||||
if let Some(pos) = buf.iter().position(|&c| c == 0) {
|
||||
str::from_utf8(&buf[0..pos]).map_err(From::from)
|
||||
} else {
|
||||
str::from_utf8(buf).map_err(From::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl super::LuksHeader for luks_phdr {
|
||||
fn version(&self) -> u16 {
|
||||
self.version
|
||||
}
|
||||
|
||||
fn cipher_name(&self) -> Result<&str, super::Error> {
|
||||
u8_buf_to_str(&self.cipherName)
|
||||
}
|
||||
|
||||
fn cipher_mode(&self) -> Result<&str, super::Error> {
|
||||
u8_buf_to_str(&self.cipherMode)
|
||||
}
|
||||
|
||||
fn hash_spec(&self) -> Result<&str, super::Error> {
|
||||
u8_buf_to_str(&self.hashSpec)
|
||||
}
|
||||
|
||||
fn payload_offset(&self) -> u32 {
|
||||
self.payloadOffset
|
||||
}
|
||||
|
||||
fn key_bytes(&self) -> u32 {
|
||||
self.keyBytes
|
||||
}
|
||||
|
||||
fn mk_digest(&self) -> &[u8] {
|
||||
&self.mkDigest
|
||||
}
|
||||
|
||||
fn mk_digest_salt(&self) -> &[u8] {
|
||||
&self.mkDigestSalt
|
||||
}
|
||||
|
||||
fn mk_digest_iterations(&self) -> u32 {
|
||||
self.mkDigestIterations
|
||||
}
|
||||
|
||||
fn uuid(&self) -> Result<uuid::Uuid, super::Error> {
|
||||
let uuid_str = try!(u8_buf_to_str(&self.uuid));
|
||||
uuid::Uuid::parse_str(uuid_str).map_err(From::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::Cursor;
|
||||
use uuid;
|
||||
|
||||
#[test]
|
||||
fn test_luks_header_from_byte_buffer() {
|
||||
let header = b"LUKS\xba\xbe\x00\x01aes\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ecb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sha256\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00 \xcf^\xb4\xc00q\xbe\xd5\xe6\x90\xc8G\xb3\x00\xbe\xba\xd052qp\x92\x0c\x9c\xa9\x07R\\y_D\x08b\xf1\xe6\x8f\x0c\xa95\xad\xdb\x15+\xa5\xd7\xa7\xbf^\x96B\x90z\x00\x00\x03\xe8a1b49d2d-8a7e-4b04-ab2a-89f3408fd198\x00\x00\x00\x00";
|
||||
let mut cursor: Cursor<&[u8]> = Cursor::new(header);
|
||||
let luks_header = BlockDevice::read_luks_header(&mut cursor).unwrap();
|
||||
|
||||
assert_eq!(luks_header.version(), 1);
|
||||
assert_eq!(luks_header.cipher_name().unwrap(), "aes");
|
||||
assert_eq!(luks_header.cipher_mode().unwrap(), "ecb");
|
||||
assert_eq!(luks_header.hash_spec().unwrap(), "sha256");
|
||||
assert_eq!(luks_header.payload_offset(), 4096);
|
||||
assert_eq!(luks_header.key_bytes(), 32);
|
||||
assert_eq!(
|
||||
luks_header.mk_digest(),
|
||||
&[
|
||||
207, 94, 180, 192, 48, 113, 190, 213, 230, 144, 200, 71, 179, 0, 190, 186, 208, 53,
|
||||
50, 113
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
luks_header.mk_digest_salt(),
|
||||
&[
|
||||
112, 146, 12, 156, 169, 7, 82, 92, 121, 95, 68, 8, 98, 241, 230, 143, 12, 169, 53,
|
||||
173, 219, 21, 43, 165, 215, 167, 191, 94, 150, 66, 144, 122
|
||||
]
|
||||
);
|
||||
assert_eq!(luks_header.mk_digest_iterations(), 1000);
|
||||
assert_eq!(
|
||||
luks_header.uuid().unwrap(),
|
||||
uuid::Uuid::parse_str("a1b49d2d-8a7e-4b04-ab2a-89f3408fd198").unwrap()
|
||||
)
|
||||
}
|
||||
}
|
78
patch/cryptsetup-rs/examples/luks_dump.rs
Normal file
78
patch/cryptsetup-rs/examples/luks_dump.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
#![deny(warnings)]
|
||||
#[warn(unused_must_use)]
|
||||
extern crate cryptsetup_rs;
|
||||
extern crate env_logger;
|
||||
|
||||
use cryptsetup_rs::*;
|
||||
use std::env;
|
||||
|
||||
fn dump_slot(crypt_device: &Luks1CryptDevice, slot: Keyslot) -> Result<()> {
|
||||
let status = match crypt_device.keyslot_status(slot) {
|
||||
crypt_keyslot_info::CRYPT_SLOT_INVALID => "INVALID",
|
||||
crypt_keyslot_info::CRYPT_SLOT_INACTIVE => "DISABLED",
|
||||
crypt_keyslot_info::CRYPT_SLOT_ACTIVE | crypt_keyslot_info::CRYPT_SLOT_ACTIVE_LAST => "ENABLED",
|
||||
};
|
||||
|
||||
println!("Key Slot {}: {}", slot, status);
|
||||
match status {
|
||||
"ENABLED" => /* TODO add keyslot information */ (),
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dump(device_path: &str) -> Result<()> {
|
||||
let dev = open(device_path)?.luks1()?;
|
||||
|
||||
println!("LUKS header information for {}", dev.device_name());
|
||||
println!();
|
||||
println!("{:<16}{}", "Version:", "1");
|
||||
println!("{:<16}{}", "Cipher name:", dev.cipher());
|
||||
println!("{:<16}{}", "Cipher mode:", dev.cipher_mode());
|
||||
println!("{:<16}{}", "Hash spec:", dev.hash_spec());
|
||||
println!("{:<16}{}", "Payload offset:", dev.payload_offset());
|
||||
println!("{:<16}{}", "MK bits:", dev.mk_bits());
|
||||
|
||||
print!("{:<16}", "MK digest:");
|
||||
for b in dev.mk_digest().iter() {
|
||||
print!("{:x} ", b);
|
||||
}
|
||||
println!();
|
||||
|
||||
let salt = dev.mk_salt();
|
||||
print!("{:<16}", "MK salt:");
|
||||
for b in salt[0..16].iter() {
|
||||
print!("{:x} ", b);
|
||||
}
|
||||
println!();
|
||||
print!("{:<16}", "");
|
||||
for b in salt[16..32].iter() {
|
||||
print!("{:x} ", b);
|
||||
}
|
||||
println!();
|
||||
|
||||
println!("{:<16}{}", "MK iterations:", dev.mk_iterations());
|
||||
println!("{:<16}{}", "UUID:", dev.uuid());
|
||||
|
||||
println!();
|
||||
|
||||
for slot in 0..8 {
|
||||
dump_slot(&dev, slot)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().skip(1).collect();
|
||||
if args.len() != 1 {
|
||||
println!("Usage: luks_dump <device path>");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
let device_path = args[0].as_str();
|
||||
|
||||
if let Err(e) = dump(device_path) {
|
||||
println!("Error: {:?}", e);
|
||||
::std::process::exit(2);
|
||||
}
|
||||
}
|
21
patch/cryptsetup-rs/libcryptsetup-sys/Cargo.toml
Normal file
21
patch/cryptsetup-rs/libcryptsetup-sys/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "libcryptsetup-sys"
|
||||
version = "0.1.1"
|
||||
authors = ["Vladimir Lushnikov <vladimir@solidninja.is>"]
|
||||
license = "LGPL-3.0"
|
||||
description = "FFI bindings to the libcryptsetup library"
|
||||
homepage = "https://github.com/solidninja/cryptsetup-rs"
|
||||
|
||||
links = "cryptsetup"
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
name = "libcryptsetup_sys"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "0.3"
|
||||
|
8
patch/cryptsetup-rs/libcryptsetup-sys/build.rs
Normal file
8
patch/cryptsetup-rs/libcryptsetup-sys/build.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
extern crate pkg_config;
|
||||
|
||||
fn main() {
|
||||
pkg_config::Config::new()
|
||||
.statik(true)
|
||||
.find("libcryptsetup")
|
||||
.unwrap();
|
||||
}
|
492
patch/cryptsetup-rs/libcryptsetup-sys/lib.rs
Normal file
492
patch/cryptsetup-rs/libcryptsetup-sys/lib.rs
Normal file
@@ -0,0 +1,492 @@
|
||||
#![deny(warnings)]
|
||||
#![allow(non_camel_case_types)]
|
||||
extern crate libc;
|
||||
|
||||
use libc::{c_char, c_double, c_int, c_uint, c_void, size_t};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub enum crypt_device {}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_log_level {
|
||||
CRYPT_LOG_NORMAL = 0,
|
||||
CRYPT_LOG_ERROR = 1,
|
||||
CRYPT_LOG_VERBOSE = 2,
|
||||
CRYPT_LOG_DEBUG = -1,
|
||||
}
|
||||
|
||||
pub type crypt_log_cb = extern "C" fn(crypt_log_level, *const c_char, *mut c_void);
|
||||
pub type crypt_confirm_cb = extern "C" fn(*const c_char, *mut c_void) -> c_int;
|
||||
pub type crypt_password_cb =
|
||||
extern "C" fn(*const c_char, *mut c_char, size_t, *mut c_void) -> c_int;
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_rng_type {
|
||||
CRYPT_RNG_URANDOM = 0,
|
||||
CRYPT_RNG_RANDOM = 1,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_device_type {
|
||||
PLAIN,
|
||||
LUKS1,
|
||||
LOOPAES,
|
||||
VERITY,
|
||||
TCRYPT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_params_plain {
|
||||
pub hash: *const c_char,
|
||||
pub offset: u64,
|
||||
pub skip: u64,
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_params_luks1 {
|
||||
pub hash: *const c_char,
|
||||
pub data_alignment: size_t,
|
||||
pub data_device: *const c_char,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_params_loopaes {
|
||||
pub hash: *const c_char,
|
||||
pub offset: u64,
|
||||
pub skip: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_params_verity {
|
||||
pub hash_name: *const c_char,
|
||||
pub data_device: *const c_char,
|
||||
pub hash_device: *const c_char,
|
||||
pub salt: *const c_char,
|
||||
pub salt_size: u32,
|
||||
pub hash_type: u32,
|
||||
pub data_block_size: u32,
|
||||
pub hash_block_size: u32,
|
||||
pub data_size: u64,
|
||||
pub hash_area_offset: u64,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_verity_flag {
|
||||
CRYPT_VERITY_NO_HEADER = (1 << 0),
|
||||
CRYPT_VERITY_CHECK_HASH = (1 << 1),
|
||||
CRYPT_VERITY_CREATE_HASH = (1 << 2),
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_params_tcrypt {
|
||||
pub passphrase: *const c_char,
|
||||
pub passphrase_size: size_t,
|
||||
pub keyfiles: *const *const c_char,
|
||||
pub keyfiles_count: c_uint,
|
||||
pub hash_name: *const c_char,
|
||||
pub cipher: *const c_char,
|
||||
pub mode: *const c_char,
|
||||
pub key_size: size_t,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_tcrypt_flag {
|
||||
CRYPT_TCRYPT_LEGACY_MODES = (1 << 0),
|
||||
CRYPT_TCRYPT_HIDDEN_HEADER = (1 << 1),
|
||||
CRYPT_TCRYPT_BACKUP_HEADER = (1 << 2),
|
||||
CRYPT_TCRYPT_SYSTEM_HEADER = (1 << 3),
|
||||
CRYPT_TCRYPT_VERA_MODES = (1 << 4),
|
||||
}
|
||||
|
||||
pub const CRYPT_ANY_SLOT: c_int = -1;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_activation_flag {
|
||||
CRYPT_ACTIVATE_READONLY = (1 << 0),
|
||||
CRYPT_ACTIVATE_NO_UUID = (1 << 1),
|
||||
CRYPT_ACTIVATE_SHARED = (1 << 2),
|
||||
CRYPT_ACTIVATE_ALLOW_DISCARDS = (1 << 3),
|
||||
CRYPT_ACTIVATE_PRIVATE = (1 << 4),
|
||||
CRYPT_ACTIVATE_CORRUPTED = (1 << 5),
|
||||
CRYPT_ACTIVATE_SAME_CPU_CRYPT = (1 << 6),
|
||||
CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS = (1 << 7),
|
||||
CRYPT_ACTIVATE_IGNORE_CORRUPTION = (1 << 8),
|
||||
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION = (1 << 9),
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS = (1 << 10),
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct crypt_active_device {
|
||||
pub offset: u64,
|
||||
pub iv_offset: u64,
|
||||
pub size: u64,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_status_info {
|
||||
CRYPT_INVALID,
|
||||
CRYPT_INACTIVE,
|
||||
CRYPT_ACTIVE,
|
||||
CRYPT_BUSY,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_keyslot_info {
|
||||
CRYPT_SLOT_INVALID,
|
||||
CRYPT_SLOT_INACTIVE,
|
||||
CRYPT_SLOT_ACTIVE,
|
||||
CRYPT_SLOT_ACTIVE_LAST,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum crypt_debug_level {
|
||||
CRYPT_DEBUG_ALL = -1,
|
||||
CRYPT_DEBUG_NONE = 0,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn crypt_init(cd: *mut *mut crypt_device, device: *const c_char) -> c_int;
|
||||
pub fn crypt_init_by_name_and_header(
|
||||
cd: *mut *mut crypt_device,
|
||||
name: *const c_char,
|
||||
header_device: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn crypt_init_by_name(cd: *mut *mut crypt_device, name: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_set_log_callback(
|
||||
cd: *mut crypt_device,
|
||||
log: Option<crypt_log_cb>,
|
||||
usrptr: *mut c_void,
|
||||
);
|
||||
pub fn crypt_log(cd: *mut crypt_device, level: crypt_log_level, msg: *const c_char);
|
||||
|
||||
pub fn crypt_set_confirm_callback(
|
||||
cd: *mut crypt_device,
|
||||
confirm: crypt_confirm_cb,
|
||||
usrptr: *mut c_void,
|
||||
);
|
||||
#[deprecated]
|
||||
pub fn crypt_set_password_callback(
|
||||
cd: *mut crypt_device,
|
||||
password: crypt_password_cb,
|
||||
usrptr: *mut c_void,
|
||||
);
|
||||
#[deprecated]
|
||||
pub fn crypt_set_timeout(cd: *mut crypt_device, timeout: u64);
|
||||
#[deprecated]
|
||||
pub fn crypt_set_password_retry(cd: *mut crypt_device, tries: c_int);
|
||||
pub fn crypt_set_iteration_time(cd: *mut crypt_device, iteration_time_ms: u64);
|
||||
#[deprecated]
|
||||
pub fn crypt_set_password_verify(cd: *mut crypt_device, password_verify: c_int);
|
||||
pub fn crypt_set_data_device(cd: *mut crypt_device, device: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_set_rng_type(cd: *mut crypt_device, rng_type: crypt_rng_type);
|
||||
pub fn crypt_get_rng_type(cd: *mut crypt_device) -> c_int;
|
||||
|
||||
pub fn crypt_memory_lock(cd: *mut crypt_device, lock: c_int) -> c_int;
|
||||
|
||||
pub fn crypt_get_type(cd: *mut crypt_device) -> *const c_char;
|
||||
|
||||
pub fn crypt_format(
|
||||
cd: *mut crypt_device,
|
||||
crypt_type: *const c_char,
|
||||
cipher: *const c_char,
|
||||
cipher_mode: *const c_char,
|
||||
uuid: *const c_char,
|
||||
volume_key: *const c_char,
|
||||
volume_key_size: size_t,
|
||||
params: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_set_uuid(cd: *mut crypt_device, uuid: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_load(
|
||||
cd: *mut crypt_device,
|
||||
requested_type: *const c_char,
|
||||
params: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_repair(
|
||||
cd: *mut crypt_device,
|
||||
requested_type: *const c_char,
|
||||
params: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_resize(cd: *mut crypt_device, name: *const c_char, new_size: u64) -> c_int;
|
||||
|
||||
pub fn crypt_suspend(cd: *mut crypt_device, name: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_resume_by_passphrase(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
) -> c_int;
|
||||
pub fn crypt_resume_by_keyfile_offset(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
keyfile_offset: size_t,
|
||||
) -> c_int;
|
||||
pub fn crypt_resume_by_keyfile(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_free(cd: *mut crypt_device);
|
||||
|
||||
pub fn crypt_keyslot_add_by_passphrase(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
new_passphrase: *const c_char,
|
||||
new_passphrase_size: size_t,
|
||||
) -> c_int;
|
||||
pub fn crypt_keyslot_change_by_passphrase(
|
||||
cd: *mut crypt_device,
|
||||
keyslot_old: c_int,
|
||||
keyslot_new: c_int,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
new_passphrase: *const c_char,
|
||||
new_passphrase_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_keyslot_add_by_keyfile_offset(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
keyfile_offset: size_t,
|
||||
new_keyfile: *const c_char,
|
||||
new_keyfile_size: size_t,
|
||||
new_keyfile_offset: size_t,
|
||||
) -> c_int;
|
||||
pub fn crypt_keyslot_add_by_keyfile(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
new_keyfile: *const c_char,
|
||||
new_keyfile_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_keyslot_add_by_volume_key(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
volume_key: *const c_char,
|
||||
volume_key_size: size_t,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_keyslot_destroy(cd: *mut crypt_device, keyslot: c_int) -> c_int;
|
||||
|
||||
pub fn crypt_get_active_device(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
cad: *mut crypt_active_device,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_activate_by_passphrase(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
flags: u32,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_activate_by_keyfile_offset(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
keyfile_offset: size_t,
|
||||
flags: u32,
|
||||
) -> c_int;
|
||||
pub fn crypt_activate_by_keyfile(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
keyslot: c_int,
|
||||
keyfile: *const c_char,
|
||||
keyfile_size: size_t,
|
||||
flags: u32,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_activate_by_volume_key(
|
||||
cd: *mut crypt_device,
|
||||
name: *const c_char,
|
||||
volume_key: *const c_char,
|
||||
volume_key_size: size_t,
|
||||
flags: u32,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_deactivate(cd: *mut crypt_device, name: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_volume_key_get(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
volume_key: *mut c_char,
|
||||
volume_key_size: *mut size_t,
|
||||
passphrase: *const c_char,
|
||||
passphrase_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_volume_key_verify(
|
||||
cd: *mut crypt_device,
|
||||
volume_key: *const c_char,
|
||||
volume_key_size: size_t,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_status(cd: *mut crypt_device, name: *const c_char) -> crypt_status_info;
|
||||
|
||||
pub fn crypt_dump(cd: *mut crypt_device) -> c_int;
|
||||
|
||||
pub fn crypt_get_cipher(cd: *mut crypt_device) -> *const c_char;
|
||||
pub fn crypt_get_cipher_mode(cd: *mut crypt_device) -> *const c_char;
|
||||
pub fn crypt_get_uuid(cd: *mut crypt_device) -> *const c_char;
|
||||
pub fn crypt_get_device_name(cd: *mut crypt_device) -> *const c_char;
|
||||
pub fn crypt_get_data_offset(cd: *mut crypt_device) -> u64;
|
||||
pub fn crypt_get_iv_offset(cd: *mut crypt_device) -> u64;
|
||||
pub fn crypt_get_volume_key_size(cd: *mut crypt_device) -> c_int;
|
||||
pub fn crypt_get_verity_info(cd: *mut crypt_device, vp: *mut crypt_params_verity);
|
||||
|
||||
pub fn crypt_benchmark(
|
||||
cd: *mut crypt_device,
|
||||
cipher: *const c_char,
|
||||
cipher_mode: *const c_char,
|
||||
volume_key_size: size_t,
|
||||
iv_size: size_t,
|
||||
buffer_size: size_t,
|
||||
encryption_mbs: *mut c_double,
|
||||
decryption_mbs: *mut c_double,
|
||||
) -> c_int;
|
||||
pub fn crypt_benchmark_kdf(
|
||||
cd: *mut crypt_device,
|
||||
kdf: *const c_char,
|
||||
hash: *const c_char,
|
||||
password: *const c_char,
|
||||
password_size: size_t,
|
||||
salt: *const c_char,
|
||||
salt_size: size_t,
|
||||
iterations_sec: *mut u64,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_keyslot_status(cd: *mut crypt_device, keyslot: c_int) -> crypt_keyslot_info;
|
||||
|
||||
pub fn crypt_keyslot_max(crypt_device_type: *const c_char) -> c_int;
|
||||
|
||||
pub fn crypt_keyslot_area(
|
||||
cd: *mut crypt_device,
|
||||
keyslot: c_int,
|
||||
offset: *mut u64,
|
||||
length: *mut u64,
|
||||
) -> c_int;
|
||||
|
||||
pub fn crypt_header_backup(
|
||||
cd: *mut crypt_device,
|
||||
requested_type: *const c_char,
|
||||
backup_file: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn crypt_header_restore(
|
||||
cd: *mut crypt_device,
|
||||
requested_type: *const c_char,
|
||||
backup_file: *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
#[deprecated]
|
||||
pub fn crypt_last_error(cd: *mut crypt_device, buf: *mut c_char, size: size_t);
|
||||
#[deprecated]
|
||||
pub fn crypt_get_error(buf: *mut c_char, size: size_t);
|
||||
|
||||
pub fn crypt_get_dir() -> *const c_char;
|
||||
|
||||
pub fn crypt_set_debug_level(level: crypt_debug_level);
|
||||
}
|
||||
|
||||
impl FromStr for crypt_device_type {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<crypt_device_type, ()> {
|
||||
match s {
|
||||
"PLAIN" => Ok(crypt_device_type::PLAIN),
|
||||
"LUKS1" => Ok(crypt_device_type::LUKS1),
|
||||
"LOOPAES" => Ok(crypt_device_type::LOOPAES),
|
||||
"VERITY" => Ok(crypt_device_type::VERITY),
|
||||
"TCRYPT" => Ok(crypt_device_type::TCRYPT),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crypt_device_type {
|
||||
pub fn to_str(&self) -> &str {
|
||||
match self {
|
||||
&crypt_device_type::PLAIN => "PLAIN",
|
||||
&crypt_device_type::LUKS1 => "LUKS1",
|
||||
&crypt_device_type::LOOPAES => "LOOPAES",
|
||||
&crypt_device_type::VERITY => "VERITY",
|
||||
&crypt_device_type::TCRYPT => "TCRYPT",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ffi::CString;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn test_device_type_conversion() {
|
||||
assert_eq!(
|
||||
Ok(crypt_device_type::PLAIN),
|
||||
crypt_device_type::from_str("PLAIN")
|
||||
);
|
||||
assert_eq!(
|
||||
Ok(crypt_device_type::LUKS1),
|
||||
crypt_device_type::from_str("LUKS1")
|
||||
);
|
||||
assert_eq!(
|
||||
Ok(crypt_device_type::LOOPAES),
|
||||
crypt_device_type::from_str("LOOPAES")
|
||||
);
|
||||
assert_eq!(
|
||||
Ok(crypt_device_type::VERITY),
|
||||
crypt_device_type::from_str("VERITY")
|
||||
);
|
||||
assert_eq!(
|
||||
Ok(crypt_device_type::TCRYPT),
|
||||
crypt_device_type::from_str("TCRYPT")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keyslot_max_gt_zero() {
|
||||
unsafe {
|
||||
let luks_type = CString::new("LUKS1").unwrap();
|
||||
assert!(crypt_keyslot_max(luks_type.as_ptr()) > 0);
|
||||
}
|
||||
}
|
||||
}
|
2
patch/cryptsetup-rs/rustfmt.toml
Normal file
2
patch/cryptsetup-rs/rustfmt.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
max_width = 120
|
||||
format_strings = false
|
377
patch/cryptsetup-rs/src/api.rs
Normal file
377
patch/cryptsetup-rs/src/api.rs
Normal file
@@ -0,0 +1,377 @@
|
||||
//! High-level API to work with `libcryptsetup` supported devices (disks)
|
||||
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use blkid_rs::{BlockDevice, LuksHeader};
|
||||
|
||||
use device;
|
||||
pub use device::enable_debug;
|
||||
use device::RawDevice;
|
||||
pub use device::{Error, Keyslot, Result};
|
||||
use raw;
|
||||
use uuid;
|
||||
|
||||
pub type Luks1CryptDeviceHandle = CryptDeviceHandle<Luks1Params>;
|
||||
|
||||
/// Builder to open a crypt device at the specified path
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use cryptsetup_rs::*;
|
||||
/// # fn foo() -> Result<()> {
|
||||
/// let device = open("/dev/loop0")?.luks1()?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<CryptDeviceOpenBuilder> {
|
||||
let cd = device::init(path.as_ref())?;
|
||||
Ok(CryptDeviceOpenBuilder {
|
||||
path: path.as_ref().to_owned(),
|
||||
cd,
|
||||
})
|
||||
}
|
||||
|
||||
/// Builder to format a crypt device at the specified path
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate uuid;
|
||||
/// # extern crate cryptsetup_rs;
|
||||
/// use cryptsetup_rs::*;
|
||||
/// use uuid::Uuid;
|
||||
///
|
||||
/// # fn foo() -> Result<()> {
|
||||
/// let uuid = Uuid::new_v4();
|
||||
/// let device = format("/dev/loop0")?
|
||||
/// .rng_type(crypt_rng_type::CRYPT_RNG_URANDOM)
|
||||
/// .iteration_time(5000)
|
||||
/// .luks1("aes", "xts-plain", "sha256", 256, Some(&uuid))?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn format<P: AsRef<Path>>(path: P) -> Result<CryptDeviceFormatBuilder> {
|
||||
let cd = device::init(path.as_ref())?;
|
||||
Ok(CryptDeviceFormatBuilder {
|
||||
path: path.as_ref().to_owned(),
|
||||
cd,
|
||||
})
|
||||
}
|
||||
|
||||
/// Read the UUID of a LUKS1 container without opening the device
|
||||
pub fn luks1_uuid<P: AsRef<Path>>(path: P) -> Result<uuid::Uuid> {
|
||||
let device_file = File::open(path.as_ref())?;
|
||||
let luks_phdr = BlockDevice::read_luks_header(device_file)?;
|
||||
let uuid = luks_phdr.uuid()?;
|
||||
Ok(uuid)
|
||||
}
|
||||
|
||||
fn load_luks1_params<P: AsRef<Path>>(path: P) -> Result<Luks1Params> {
|
||||
let device_file = File::open(path.as_ref())?;
|
||||
let luks_phdr = BlockDevice::read_luks_header(device_file)?;
|
||||
Luks1Params::from(luks_phdr)
|
||||
}
|
||||
|
||||
/// Struct containing state for the `open()` builder
|
||||
pub struct CryptDeviceOpenBuilder {
|
||||
path: PathBuf,
|
||||
cd: RawDevice,
|
||||
}
|
||||
|
||||
impl CryptDeviceOpenBuilder {
|
||||
/// Loads an existing LUKS1 crypt device
|
||||
pub fn luks1(self: CryptDeviceOpenBuilder) -> Result<CryptDeviceHandle<Luks1Params>> {
|
||||
let _ = device::load(&self.cd, raw::crypt_device_type::LUKS1);
|
||||
let params = load_luks1_params(&self.path)?;
|
||||
Ok(CryptDeviceHandle {
|
||||
cd: self.cd,
|
||||
path: self.path,
|
||||
params,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct containing state for the `format()` builder
|
||||
pub struct CryptDeviceFormatBuilder {
|
||||
path: PathBuf,
|
||||
cd: RawDevice,
|
||||
}
|
||||
|
||||
impl CryptDeviceFormatBuilder {
|
||||
/// Set the iteration time for the `PBKDF2` function. Note that this does not affect the MK iterations.
|
||||
pub fn iteration_time(mut self, iteration_time_ms: u64) -> Self {
|
||||
device::set_iteration_time(&mut self.cd, iteration_time_ms);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the random number generator to use
|
||||
pub fn rng_type(mut self, rng_type: raw::crypt_rng_type) -> Self {
|
||||
device::set_rng_type(&mut self.cd, rng_type);
|
||||
self
|
||||
}
|
||||
|
||||
/// Formats a new block device as a LUKS1 crypt device with the specified parameters
|
||||
pub fn luks1(
|
||||
mut self: CryptDeviceFormatBuilder,
|
||||
cipher: &str,
|
||||
cipher_mode: &str,
|
||||
hash: &str,
|
||||
mk_bits: usize,
|
||||
maybe_uuid: Option<&uuid::Uuid>,
|
||||
) -> Result<CryptDeviceHandle<Luks1Params>> {
|
||||
let _ = device::luks1_format(&mut self.cd, cipher, cipher_mode, hash, mk_bits, maybe_uuid)?;
|
||||
let params = load_luks1_params(&self.path)?;
|
||||
Ok(CryptDeviceHandle {
|
||||
cd: self.cd,
|
||||
path: self.path,
|
||||
params,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait representing common operations on a crypt device
|
||||
pub trait CryptDevice {
|
||||
/// Path the device was opened/created with
|
||||
fn path(&self) -> &Path;
|
||||
|
||||
/// Name of cipher used
|
||||
fn cipher(&self) -> &str;
|
||||
|
||||
/// Name of cipher mode used
|
||||
fn cipher_mode(&self) -> &str;
|
||||
|
||||
/// Path to the underlying device (as reported by `libcryptsetup`)
|
||||
fn device_name(&self) -> &str;
|
||||
|
||||
/// Random number generator used for operations on this crypt device
|
||||
fn rng_type(&self) -> raw::crypt_rng_type;
|
||||
|
||||
/// Sets the random number generator to use
|
||||
fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type);
|
||||
|
||||
/// Sets the iteration time for the `PBKDF2` function. Note that this does not affect the MK iterations.
|
||||
fn set_iteration_time(&mut self, iteration_time_ms: u64);
|
||||
|
||||
/// Volume key size (in bytes)
|
||||
fn volume_key_size(&self) -> u8;
|
||||
}
|
||||
|
||||
/// Trait for querying the device type at runtime
|
||||
pub trait CryptDeviceType {
|
||||
/// Type of the crypt device
|
||||
fn device_type(&self) -> raw::crypt_device_type;
|
||||
}
|
||||
|
||||
/// Trait representing specific operations on a LUKS1 device
|
||||
pub trait Luks1CryptDevice {
|
||||
/// Activate the crypt device, and give it the specified name
|
||||
fn activate(&mut self, name: &str, key: &[u8]) -> Result<Keyslot>;
|
||||
|
||||
/// Add a new keyslot with the specified key
|
||||
fn add_keyslot(
|
||||
&mut self,
|
||||
key: &[u8],
|
||||
maybe_prev_key: Option<&[u8]>,
|
||||
maybe_keyslot: Option<Keyslot>,
|
||||
) -> Result<Keyslot>;
|
||||
|
||||
/// Replace an old key with a new one
|
||||
fn update_keyslot(&mut self, key: &[u8], prev_key: &[u8], maybe_keyslot: Option<Keyslot>) -> Result<Keyslot>;
|
||||
|
||||
/// Destroy (and disable) key slot
|
||||
fn destroy_keyslot(&mut self, slot: Keyslot) -> Result<()>;
|
||||
|
||||
/// Dump text-formatted information about the current device to stdout
|
||||
fn dump(&self);
|
||||
|
||||
/// Get the hash algorithm used
|
||||
fn hash_spec(&self) -> &str;
|
||||
|
||||
/// Get status of key slot
|
||||
fn keyslot_status(&self, keyslot: Keyslot) -> raw::crypt_keyslot_info;
|
||||
|
||||
/// Number of bits in the master key
|
||||
fn mk_bits(&self) -> u32;
|
||||
|
||||
/// Master key header digest
|
||||
fn mk_digest(&self) -> &[u8; 20];
|
||||
|
||||
/// Master key `PBKDF2` iterations
|
||||
fn mk_iterations(&self) -> u32;
|
||||
|
||||
/// Master key salt
|
||||
fn mk_salt(&self) -> &[u8; 32];
|
||||
|
||||
/// Get the offset of the payload
|
||||
fn payload_offset(&self) -> u32;
|
||||
|
||||
/// UUID of the current device
|
||||
fn uuid(&self) -> uuid::Uuid;
|
||||
}
|
||||
|
||||
/// An opaque handle on an initialized crypt device
|
||||
#[derive(PartialEq)]
|
||||
pub struct CryptDeviceHandle<P: fmt::Debug> {
|
||||
/// Pointer to the raw device
|
||||
cd: RawDevice,
|
||||
|
||||
/// Path to the crypt device (useful for diagnostics)
|
||||
path: PathBuf,
|
||||
|
||||
/// Additional parameters depending on type of crypt device opened
|
||||
params: P,
|
||||
}
|
||||
|
||||
impl<P: fmt::Debug> fmt::Debug for CryptDeviceHandle<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"CryptDeviceHandle(path={}, raw={:p}, params={:?})",
|
||||
self.path.display(),
|
||||
self.cd,
|
||||
self.params
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: fmt::Debug> Drop for CryptDeviceHandle<P> {
|
||||
fn drop(&mut self) {
|
||||
device::free(&mut self.cd);
|
||||
self.cd = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: fmt::Debug> CryptDevice for CryptDeviceHandle<P> {
|
||||
fn path(&self) -> &Path {
|
||||
self.path.as_ref()
|
||||
}
|
||||
|
||||
fn cipher(&self) -> &str {
|
||||
device::cipher(&self.cd).expect("Initialised device should have cipher")
|
||||
}
|
||||
|
||||
fn cipher_mode(&self) -> &str {
|
||||
device::cipher_mode(&self.cd).expect("Initialised device should have cipher mode")
|
||||
}
|
||||
|
||||
fn device_name(&self) -> &str {
|
||||
device::device_name(&self.cd).expect("Initialised device should have an underlying path")
|
||||
}
|
||||
|
||||
fn rng_type(&self) -> raw::crypt_rng_type {
|
||||
device::rng_type(&self.cd)
|
||||
}
|
||||
|
||||
fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type) {
|
||||
device::set_rng_type(&mut self.cd, rng_type)
|
||||
}
|
||||
|
||||
fn set_iteration_time(&mut self, iteration_time_ms: u64) {
|
||||
device::set_iteration_time(&mut self.cd, iteration_time_ms)
|
||||
}
|
||||
|
||||
fn volume_key_size(&self) -> u8 {
|
||||
device::volume_key_size(&self.cd)
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct for storing LUKS1 parameters in memory
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Luks1Params {
|
||||
hash_spec: String,
|
||||
payload_offset: u32,
|
||||
mk_bits: u32,
|
||||
mk_digest: [u8; 20],
|
||||
mk_salt: [u8; 32],
|
||||
mk_iterations: u32,
|
||||
}
|
||||
|
||||
impl Luks1Params {
|
||||
fn from(header: impl LuksHeader) -> Result<Luks1Params> {
|
||||
let hash_spec = header.hash_spec()?.to_owned();
|
||||
let payload_offset = header.payload_offset();
|
||||
let mk_bits = header.key_bytes() * 8;
|
||||
let mut mk_digest = [0u8; 20];
|
||||
mk_digest.copy_from_slice(header.mk_digest());
|
||||
let mut mk_salt = [0u8; 32];
|
||||
mk_salt.copy_from_slice(header.mk_digest_salt());
|
||||
let mk_iterations = header.mk_digest_iterations();
|
||||
Ok(Luks1Params {
|
||||
hash_spec,
|
||||
payload_offset,
|
||||
mk_bits,
|
||||
mk_digest,
|
||||
mk_salt,
|
||||
mk_iterations,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Luks1CryptDevice for CryptDeviceHandle<Luks1Params> {
|
||||
fn activate(&mut self, name: &str, key: &[u8]) -> Result<Keyslot> {
|
||||
device::luks_activate(&mut self.cd, name, key)
|
||||
}
|
||||
|
||||
fn add_keyslot(
|
||||
&mut self,
|
||||
key: &[u8],
|
||||
maybe_prev_key: Option<&[u8]>,
|
||||
maybe_keyslot: Option<Keyslot>,
|
||||
) -> Result<Keyslot> {
|
||||
device::luks_add_keyslot(&mut self.cd, key, maybe_prev_key, maybe_keyslot)
|
||||
}
|
||||
|
||||
fn update_keyslot(&mut self, key: &[u8], prev_key: &[u8], maybe_keyslot: Option<Keyslot>) -> Result<Keyslot> {
|
||||
device::luks_update_keyslot(&mut self.cd, key, prev_key, maybe_keyslot)
|
||||
}
|
||||
|
||||
fn destroy_keyslot(&mut self, slot: Keyslot) -> Result<()> {
|
||||
device::luks_destroy_keyslot(&mut self.cd, slot)
|
||||
}
|
||||
|
||||
fn dump(&self) {
|
||||
device::dump(&self.cd).expect("Dump should be fine for initialised device")
|
||||
}
|
||||
|
||||
fn hash_spec(&self) -> &str {
|
||||
self.params.hash_spec.as_ref()
|
||||
}
|
||||
|
||||
fn keyslot_status(&self, keyslot: Keyslot) -> raw::crypt_keyslot_info {
|
||||
device::keyslot_status(&self.cd, keyslot)
|
||||
}
|
||||
|
||||
fn mk_bits(&self) -> u32 {
|
||||
self.params.mk_bits
|
||||
}
|
||||
|
||||
fn mk_digest(&self) -> &[u8; 20] {
|
||||
&self.params.mk_digest
|
||||
}
|
||||
|
||||
fn mk_iterations(&self) -> u32 {
|
||||
self.params.mk_iterations
|
||||
}
|
||||
|
||||
fn mk_salt(&self) -> &[u8; 32] {
|
||||
&self.params.mk_salt
|
||||
}
|
||||
|
||||
fn payload_offset(&self) -> u32 {
|
||||
self.params.payload_offset
|
||||
}
|
||||
|
||||
fn uuid(&self) -> uuid::Uuid {
|
||||
device::uuid(&self.cd).expect("LUKS1 device should have UUID")
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptDeviceType for CryptDeviceHandle<Luks1Params> {
|
||||
fn device_type(&self) -> raw::crypt_device_type {
|
||||
raw::crypt_device_type::LUKS1
|
||||
}
|
||||
}
|
319
patch/cryptsetup-rs/src/device.rs
Normal file
319
patch/cryptsetup-rs/src/device.rs
Normal file
@@ -0,0 +1,319 @@
|
||||
//! Low-level cryptsetup binding that sits directly on top of the `libcryptsetup` C API
|
||||
//!
|
||||
//! Consider using the high-level binding in the `api` module instead
|
||||
|
||||
use std::ffi;
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::result;
|
||||
use std::str;
|
||||
|
||||
use blkid_rs;
|
||||
use errno;
|
||||
use libc;
|
||||
use raw;
|
||||
use uuid;
|
||||
|
||||
/// Raw pointer to the underlying `crypt_device` opaque struct
|
||||
pub type RawDevice = *mut raw::crypt_device;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Error that originates from `libcryptsetup` (with numeric error code)
|
||||
CryptsetupError(errno::Errno),
|
||||
/// IO error
|
||||
IOError(::std::io::Error),
|
||||
/// Error from the blkid-rs library (while reading LUKS1 header)
|
||||
BlkidError(blkid_rs::Error),
|
||||
}
|
||||
|
||||
impl From<::std::io::Error> for Error {
|
||||
fn from(e: ::std::io::Error) -> Self {
|
||||
Error::IOError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<blkid_rs::Error> for Error {
|
||||
fn from(e: blkid_rs::Error) -> Self {
|
||||
Error::BlkidError(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
pub type Keyslot = u8;
|
||||
|
||||
const ANY_KEYSLOT: libc::c_int = -1 as libc::c_int;
|
||||
|
||||
fn str_from_c_str<'a>(c_str: *const libc::c_char) -> Option<&'a str> {
|
||||
if c_str.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { Some(ffi::CStr::from_ptr(c_str).to_str().unwrap()) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! crypt_error {
|
||||
($res:expr) => {
|
||||
Err(Error::CryptsetupError(errno::Errno(-$res)))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! check_crypt_error {
|
||||
($res:expr) => {
|
||||
if $res != 0 {
|
||||
crypt_error!($res)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Log function callback used by `libcryptsetup`
|
||||
#[allow(unused)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cryptsetup_rs_log_callback(
|
||||
level: raw::crypt_log_level,
|
||||
message: *const libc::c_char,
|
||||
usrptr: *mut libc::c_void,
|
||||
) {
|
||||
let msg = str_from_c_str(message).unwrap();
|
||||
match level {
|
||||
raw::crypt_log_level::CRYPT_LOG_NORMAL => info!("{}", msg.trim_right()),
|
||||
raw::crypt_log_level::CRYPT_LOG_ERROR => error!("{}", msg.trim_right()),
|
||||
raw::crypt_log_level::CRYPT_LOG_VERBOSE => debug!("{}", msg.trim_right()),
|
||||
raw::crypt_log_level::CRYPT_LOG_DEBUG => debug!("{}", msg.trim_right()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable internal `libcryptsetup` debugging
|
||||
pub fn enable_debug(debug: bool) {
|
||||
if debug {
|
||||
unsafe { raw::crypt_set_debug_level(raw::crypt_debug_level::CRYPT_DEBUG_ALL) };
|
||||
} else {
|
||||
unsafe { raw::crypt_set_debug_level(raw::crypt_debug_level::CRYPT_DEBUG_NONE) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialise crypt device and check if provided device exists
|
||||
pub fn init<P: AsRef<Path>>(path: P) -> Result<RawDevice> {
|
||||
let mut cd = ptr::null_mut();
|
||||
let c_path = ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap();
|
||||
|
||||
let res = unsafe { raw::crypt_init(&mut cd as *mut *mut raw::crypt_device, c_path.as_ptr()) };
|
||||
|
||||
if res != 0 {
|
||||
crypt_error!(res)
|
||||
} else {
|
||||
unsafe {
|
||||
raw::crypt_set_log_callback(cd, Some(cryptsetup_rs_log_callback), ptr::null_mut());
|
||||
}
|
||||
Ok(cd)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load crypt device parameters from the on-disk header
|
||||
///
|
||||
/// Note that typically you cannot query the crypt device for information before this function is
|
||||
/// called.
|
||||
pub fn load(cd: &RawDevice, requested_type: raw::crypt_device_type) -> Result<()> {
|
||||
let c_type = ffi::CString::new(requested_type.to_str()).unwrap();
|
||||
|
||||
let res = unsafe { raw::crypt_load(*cd, c_type.as_ptr(), ptr::null_mut()) };
|
||||
|
||||
check_crypt_error!(res)
|
||||
}
|
||||
|
||||
/// Get the cipher used by this crypt device
|
||||
pub fn cipher<'a>(cd: &'a RawDevice) -> Option<&'a str> {
|
||||
let c_cipher = unsafe { raw::crypt_get_cipher(*cd) };
|
||||
str_from_c_str(c_cipher)
|
||||
}
|
||||
|
||||
/// Get the cipher mode used by this crypt device
|
||||
pub fn cipher_mode<'a>(cd: &'a RawDevice) -> Option<&'a str> {
|
||||
let c_cipher_mode = unsafe { raw::crypt_get_cipher_mode(*cd) };
|
||||
str_from_c_str(c_cipher_mode)
|
||||
}
|
||||
|
||||
/// Get the path to the device (as `libcryptsetup` sees it)
|
||||
pub fn device_name<'a>(cd: &'a RawDevice) -> Option<&'a str> {
|
||||
let c_device_name = unsafe { raw::crypt_get_device_name(*cd) };
|
||||
str_from_c_str(c_device_name)
|
||||
}
|
||||
|
||||
/// Dump text-formatted information about this device to the console
|
||||
pub fn dump(cd: &RawDevice) -> Result<()> {
|
||||
let res = unsafe { raw::crypt_dump(*cd) };
|
||||
check_crypt_error!(res)
|
||||
}
|
||||
|
||||
/// Releases crypt device context and memory
|
||||
pub fn free(cd: &mut RawDevice) {
|
||||
unsafe { raw::crypt_free(*cd) }
|
||||
}
|
||||
|
||||
/// Activate device based on provided key ("passphrase")
|
||||
pub fn luks_activate(cd: &mut RawDevice, name: &str, key: &[u8]) -> Result<Keyslot> {
|
||||
let c_name = ffi::CString::new(name).unwrap();
|
||||
let c_passphrase_len = key.len() as libc::size_t;
|
||||
// cast the passphrase to a pointer directly - it will not be NUL terminated but the passed length is used
|
||||
let c_passphrase = key as *const [u8] as *const libc::c_char;
|
||||
|
||||
let res = unsafe {
|
||||
raw::crypt_activate_by_passphrase(*cd, c_name.as_ptr(), ANY_KEYSLOT, c_passphrase, c_passphrase_len, 0u32)
|
||||
};
|
||||
|
||||
if res < 0 {
|
||||
crypt_error!(res)
|
||||
} else {
|
||||
Ok(res as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add key slot using provided passphrase. If there is no previous passphrase, use the volume key
|
||||
/// that is in-memory to add the new key slot.
|
||||
pub fn luks_add_keyslot(
|
||||
cd: &mut RawDevice,
|
||||
key: &[u8],
|
||||
maybe_prev_key: Option<&[u8]>,
|
||||
maybe_keyslot: Option<Keyslot>,
|
||||
) -> Result<Keyslot> {
|
||||
let c_key_len = key.len() as libc::size_t;
|
||||
let c_key = key as *const [u8] as *const libc::c_char;;
|
||||
let c_keyslot = maybe_keyslot
|
||||
.map(|k| k as libc::c_int)
|
||||
.unwrap_or(ANY_KEYSLOT as libc::c_int);
|
||||
|
||||
let res = if let Some(prev_key) = maybe_prev_key {
|
||||
let c_prev_key_len = prev_key.len() as libc::size_t;
|
||||
let c_prev_key = prev_key as *const [u8] as *const libc::c_char;;
|
||||
|
||||
unsafe { raw::crypt_keyslot_add_by_passphrase(*cd, c_keyslot, c_prev_key, c_prev_key_len, c_key, c_key_len) }
|
||||
} else {
|
||||
unsafe {
|
||||
raw::crypt_keyslot_add_by_volume_key(*cd, c_keyslot, ptr::null(), 0 as libc::size_t, c_key, c_key_len)
|
||||
}
|
||||
};
|
||||
|
||||
if res < 0 {
|
||||
crypt_error!(res)
|
||||
} else {
|
||||
Ok(res as Keyslot)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add key slot using provided passphrase. If there is no previous passphrase, use the volume key
|
||||
/// that is in-memory to add the new key slot.
|
||||
pub fn luks_update_keyslot(
|
||||
cd: &mut RawDevice,
|
||||
key: &[u8],
|
||||
prev_key: &[u8],
|
||||
maybe_keyslot: Option<Keyslot>,
|
||||
) -> Result<Keyslot> {
|
||||
let c_key_len = key.len() as libc::size_t;
|
||||
let c_key = key as *const [u8] as *const libc::c_char;;
|
||||
let c_keyslot = maybe_keyslot
|
||||
.map(|k| k as libc::c_int)
|
||||
.unwrap_or(ANY_KEYSLOT as libc::c_int);
|
||||
|
||||
let c_prev_key_len = prev_key.len() as libc::size_t;
|
||||
let c_prev_key = prev_key as *const [u8] as *const libc::c_char;;
|
||||
|
||||
let res = unsafe {
|
||||
raw::crypt_keyslot_change_by_passphrase(*cd, c_keyslot, c_keyslot, c_prev_key, c_prev_key_len, c_key, c_key_len)
|
||||
};
|
||||
|
||||
if res < 0 {
|
||||
crypt_error!(res)
|
||||
} else {
|
||||
Ok(res as Keyslot)
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroy (and disable) key slot
|
||||
pub fn luks_destroy_keyslot(cd: &mut RawDevice, keyslot: Keyslot) -> Result<()> {
|
||||
let res = unsafe { raw::crypt_keyslot_destroy(*cd, keyslot as libc::c_int) };
|
||||
if res < 0 {
|
||||
crypt_error!(res)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a new crypt device but do not activate it
|
||||
///
|
||||
/// Note this does not add an active keyslot
|
||||
pub fn luks1_format(
|
||||
cd: &mut RawDevice,
|
||||
cipher: &str,
|
||||
cipher_mode: &str,
|
||||
hash: &str,
|
||||
mk_bits: usize,
|
||||
maybe_uuid: Option<&uuid::Uuid>,
|
||||
) -> Result<()> {
|
||||
let c_cipher = ffi::CString::new(cipher).unwrap();
|
||||
let c_cipher_mode = ffi::CString::new(cipher_mode).unwrap();
|
||||
let c_hash = ffi::CString::new(hash).unwrap();
|
||||
let c_uuid = maybe_uuid.map(|uuid| ffi::CString::new(uuid.hyphenated().to_string()).unwrap());
|
||||
|
||||
let mut luks_params = raw::crypt_params_luks1 {
|
||||
hash: c_hash.as_ptr(),
|
||||
data_alignment: 0,
|
||||
data_device: ptr::null(),
|
||||
};
|
||||
let c_luks_params: *mut raw::crypt_params_luks1 = &mut luks_params;
|
||||
let c_luks_type = ffi::CString::new(raw::crypt_device_type::LUKS1.to_str()).unwrap();
|
||||
let c_uuid_ptr = c_uuid.as_ref().map(|u| u.as_ptr()).unwrap_or(ptr::null());
|
||||
let res = unsafe {
|
||||
raw::crypt_format(
|
||||
*cd,
|
||||
c_luks_type.as_ptr(),
|
||||
c_cipher.as_ptr(),
|
||||
c_cipher_mode.as_ptr(),
|
||||
c_uuid_ptr,
|
||||
ptr::null(),
|
||||
mk_bits / 8,
|
||||
c_luks_params as *mut libc::c_void,
|
||||
)
|
||||
};
|
||||
|
||||
check_crypt_error!(res)
|
||||
}
|
||||
|
||||
/// Get which RNG is used
|
||||
pub fn rng_type(cd: &RawDevice) -> raw::crypt_rng_type {
|
||||
unsafe {
|
||||
let res = raw::crypt_get_rng_type(*cd);
|
||||
mem::transmute(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the number of milliseconds for `PBKDF2` function iteration
|
||||
pub fn set_iteration_time(cd: &mut RawDevice, iteration_time_ms: u64) {
|
||||
unsafe {
|
||||
raw::crypt_set_iteration_time(*cd, iteration_time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set which RNG is used
|
||||
pub fn set_rng_type(cd: &mut RawDevice, rng_type: raw::crypt_rng_type) {
|
||||
unsafe { raw::crypt_set_rng_type(*cd, rng_type) }
|
||||
}
|
||||
|
||||
/// Get information about a keyslot
|
||||
pub fn keyslot_status(cd: &RawDevice, slot: Keyslot) -> raw::crypt_keyslot_info {
|
||||
unsafe { raw::crypt_keyslot_status(*cd, slot as libc::c_int) }
|
||||
}
|
||||
|
||||
/// Get size in bytes of the volume key
|
||||
pub fn volume_key_size(cd: &RawDevice) -> u8 {
|
||||
let res = unsafe { raw::crypt_get_volume_key_size(*cd) };
|
||||
res as u8
|
||||
}
|
||||
|
||||
/// Get device UUID
|
||||
pub fn uuid<'a>(cd: &'a RawDevice) -> Option<uuid::Uuid> {
|
||||
let c_uuid_str = unsafe { raw::crypt_get_uuid(*cd) };
|
||||
str_from_c_str(c_uuid_str).and_then(|uuid_str| uuid::Uuid::parse_str(uuid_str).ok())
|
||||
}
|
32
patch/cryptsetup-rs/src/lib.rs
Normal file
32
patch/cryptsetup-rs/src/lib.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! Rust bindings to `libcryptsetup` - working with encrypted disks on Linux
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! See `api` module documentation for more.
|
||||
//!
|
||||
//! ```
|
||||
//! use cryptsetup_rs::*;
|
||||
//! # fn foo() -> Result<()> {
|
||||
//! let device = open("/dev/loop0")?.luks1()?;
|
||||
//! println!("Device UUID: {}", device.uuid());
|
||||
//! println!("Device cipher: {}", device.cipher());
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#[warn(unused_must_use)]
|
||||
extern crate blkid_rs;
|
||||
extern crate errno;
|
||||
extern crate libc;
|
||||
extern crate libcryptsetup_sys as raw;
|
||||
extern crate uuid;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod api;
|
||||
pub mod device;
|
||||
|
||||
pub use api::{enable_debug, format, luks1_uuid, open};
|
||||
pub use api::{CryptDevice, CryptDeviceType, Error, Keyslot, Luks1CryptDevice, Luks1CryptDeviceHandle, Result};
|
||||
pub use raw::{crypt_device_type, crypt_keyslot_info, crypt_rng_type};
|
72
patch/cryptsetup-rs/tests/tests.rs
Normal file
72
patch/cryptsetup-rs/tests/tests.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate cryptsetup_rs;
|
||||
extern crate env_logger;
|
||||
extern crate log;
|
||||
extern crate tempdir;
|
||||
extern crate uuid;
|
||||
|
||||
#[macro_use]
|
||||
extern crate expectest;
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
use expectest::prelude::*;
|
||||
use tempdir::TempDir;
|
||||
use uuid::Uuid;
|
||||
|
||||
use cryptsetup_rs::*;
|
||||
|
||||
struct TestContext {
|
||||
dir: TempDir,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl TestContext {
|
||||
fn new(name: String) -> TestContext {
|
||||
env_logger::init();
|
||||
cryptsetup_rs::enable_debug(true);
|
||||
let dir = tempdir::TempDir::new(&name).unwrap();
|
||||
TestContext { name, dir }
|
||||
}
|
||||
|
||||
fn new_crypt_device(&self) -> api::CryptDeviceFormatBuilder {
|
||||
let crypt_file = self.dir.path().join(format!("{}.image", self.name));
|
||||
let dd_status = Command::new("dd")
|
||||
.arg("if=/dev/zero")
|
||||
.arg(format!("of={}", crypt_file.display()))
|
||||
.arg("bs=1M")
|
||||
.arg("count=10")
|
||||
.status()
|
||||
.unwrap();
|
||||
if !dd_status.success() {
|
||||
panic!("Failed to create disk image at {}", crypt_file.display());
|
||||
}
|
||||
|
||||
cryptsetup_rs::format(crypt_file).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_new_luks1_cryptdevice_no_errors() {
|
||||
let ctx = TestContext::new("new_luks1_cryptdevice".to_string());
|
||||
let uuid = Uuid::new_v4();
|
||||
|
||||
let device_format = ctx.new_crypt_device()
|
||||
.rng_type(crypt_rng_type::CRYPT_RNG_URANDOM)
|
||||
.iteration_time(42);
|
||||
|
||||
let mut dev = device_format
|
||||
.luks1("aes", "xts-plain", "sha256", 256, Some(&uuid))
|
||||
.expect("LUKS format should succeed");
|
||||
|
||||
dev.dump();
|
||||
|
||||
expect!(dev.uuid()).to(be_equal_to(uuid));
|
||||
expect!(dev.device_type()).to(be_equal_to(crypt_device_type::LUKS1));
|
||||
expect!(dev.cipher()).to(be_equal_to("aes"));
|
||||
expect!(dev.cipher_mode()).to(be_equal_to("xts-plain"));
|
||||
expect!(dev.volume_key_size()).to(be_equal_to(32));
|
||||
|
||||
expect!(dev.add_keyslot(b"hello world", None, Some(3))).to(be_ok().value(3));
|
||||
}
|
Reference in New Issue
Block a user