xts-mode

XTS block mode implementation in Rust.

Currently this implementation supports only ciphers with 128-bit (16-byte) block size (distinct from key size). Note that AES-256 uses 128-bit blocks, so it works with this crate. If you require other cipher block sizes, please open an issue.

Examples:

Encrypting and decrypting multiple sectors at a time: ```rust use aes::{Aes128, cipher::KeyInit, cipher::genericarray::GenericArray}; use xtsmode::{Xts128, gettweakdefault};

// Load the encryption key let key = [1; 32]; let plaintext = [5; 0x400];

// Load the data to be encrypted let mut buffer = plaintext.to_owned();

let cipher1 = Aes128::new(GenericArray::fromslice(&key[..16])); let cipher2 = Aes128::new(GenericArray::fromslice(&key[16..]));

let xts = Xts128::::new(cipher1, cipher2);

let sectorsize = 0x200; let firstsector_index = 0;

// Encrypt data in the buffer xts.encryptarea(&mut buffer, sectorsize, firstsectorindex, gettweakdefault);

// Decrypt data in the buffer xts.decryptarea(&mut buffer, sectorsize, firstsectorindex, gettweakdefault);

assert_eq!(&buffer[..], &plaintext[..]); ```

AES-256 works too: ```rust use aes::{Aes256, cipher::KeyInit, cipher::genericarray::GenericArray}; use xtsmode::{Xts128, gettweakdefault};

// Load the encryption key let key = [1; 64]; let plaintext = [5; 0x400];

// Load the data to be encrypted let mut buffer = plaintext.to_owned();

let cipher1 = Aes256::new(GenericArray::fromslice(&key[..32])); let cipher2 = Aes256::new(GenericArray::fromslice(&key[32..]));

let xts = Xts128::::new(cipher1, cipher2);

let sectorsize = 0x200; let firstsector_index = 0;

xts.encryptarea(&mut buffer, sectorsize, firstsectorindex, gettweakdefault);

xts.decryptarea(&mut buffer, sectorsize, firstsectorindex, gettweakdefault);

assert_eq!(&buffer[..], &plaintext[..]); ```

Encrypting and decrypting a single sector: ```rust use aes::{Aes128, cipher::KeyInit, cipher::genericarray::GenericArray}; use xtsmode::{Xts128, gettweakdefault};

// Load the encryption key let key = [1; 32]; let plaintext = [5; 0x200];

// Load the data to be encrypted let mut buffer = plaintext.to_owned();

let cipher1 = Aes128::new(GenericArray::fromslice(&key[..16])); let cipher2 = Aes128::new(GenericArray::fromslice(&key[16..]));

let xts = Xts128::::new(cipher1, cipher2);

let tweak = gettweakdefault(0); // 0 is the sector index

// Encrypt data in the buffer xts.encrypt_sector(&mut buffer, tweak);

// Decrypt data in the buffer xts.decrypt_sector(&mut buffer, tweak);

assert_eq!(&buffer[..], &plaintext[..]); ```

Decrypting a NCA (nintendo content archive) header: ```rust use aes::{Aes128, cipher::KeyInit, cipher::genericarray::GenericArray}; use xtsmode::{Xts128, gettweakdefault};

pub fn getnintendotweak(sectorindex: u128) -> [u8; 0x10] { sectorindex.tobebytes() }

// Load the header key let header_key = &[0; 0x20];

// Read into buffer header to be decrypted let mut buffer = vec![0; 0xC00];

let cipher1 = Aes128::new(GenericArray::fromslice(&headerkey[..0x10])); let cipher2 = Aes128::new(GenericArray::fromslice(&headerkey[0x10..]));

let mut xts = Xts128::new(cipher1, cipher2);

// Decrypt the first 0x400 bytes of the header in 0x200 sections xts.decryptarea(&mut buffer[0..0x400], 0x200, 0, getnintendo_tweak);

let magic = &buffer[0x200..0x204]; assert_eq!(magic, b"NCA3"); // In older NCA versions the section index used in header encryption was different

// Decrypt the rest of the header xts.decryptarea(&mut buffer[0x400..0xC00], 0x200, 2, getnintendo_tweak); ```