| // Copyright (C) 2017-2018 Baidu, Inc. All Rights Reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in |
| // the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Baidu, Inc., nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #![crate_name = "cryptosampleenclave"] |
| #![crate_type = "staticlib"] |
| |
| #![cfg_attr(not(target_env = "sgx"), no_std)] |
| #![cfg_attr(target_env = "sgx", feature(rustc_private))] |
| |
| extern crate sgx_types; |
| extern crate sgx_tcrypto; |
| extern crate sgx_trts; |
| #[cfg(not(target_env = "sgx"))] |
| #[macro_use] |
| extern crate sgx_tstd as std; |
| |
| use sgx_types::*; |
| use sgx_tcrypto::*; |
| use sgx_trts::memeq::ConsttimeMemEq; |
| use std::vec::Vec; |
| use std::slice; |
| use std::ptr; |
| |
| /// A Ecall function takes a string and output its SHA256 digest. |
| /// |
| /// # Parameters |
| /// |
| /// **input_str** |
| /// |
| /// A raw pointer to the string to be calculated. |
| /// |
| /// **some_len** |
| /// |
| /// An unsigned int indicates the length of input string |
| /// |
| /// **hash** |
| /// |
| /// A const reference to [u8;32] array, which is the destination buffer which contains the SHA256 digest, caller allocated. |
| /// |
| /// # Return value |
| /// |
| /// **SGX_SUCCESS** on success. The SHA256 digest is stored in the destination buffer. |
| /// |
| /// # Requirements |
| /// |
| /// Caller allocates the input buffer and output buffer. |
| /// |
| /// # Errors |
| /// |
| /// **SGX_ERROR_INVALID_PARAMETER** |
| /// |
| /// Indicates the parameter is invalid |
| #[no_mangle] |
| pub extern "C" fn calc_sha256(input_str: *const u8, |
| some_len: usize, |
| hash: &mut [u8;32]) -> sgx_status_t { |
| |
| println!("calc_sha256 invoked!"); |
| |
| // First, build a slice for input_str |
| let input_slice = unsafe { slice::from_raw_parts(input_str, some_len) }; |
| |
| // slice::from_raw_parts does not guarantee the length, we need a check |
| if input_slice.len() != some_len { |
| return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; |
| } |
| |
| println!("Input string len = {}, input len = {}", input_slice.len(), some_len); |
| |
| // Second, convert the vector to a slice and calculate its SHA256 |
| let result = rsgx_sha256_slice(&input_slice); |
| |
| // Third, copy back the result |
| match result { |
| Ok(output_hash) => *hash = output_hash, |
| Err(x) => return x |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |
| |
| /// An AES-GCM-128 encrypt function sample. |
| /// |
| /// # Parameters |
| /// |
| /// **key** |
| /// |
| /// Key used in AES encryption, typed as &[u8;16]. |
| /// |
| /// **plaintext** |
| /// |
| /// Plain text to be encrypted. |
| /// |
| /// **text_len** |
| /// |
| /// Length of plain text, unsigned int. |
| /// |
| /// **iv** |
| /// |
| /// Initialization vector of AES encryption, typed as &[u8;12]. |
| /// |
| /// **ciphertext** |
| /// |
| /// A pointer to destination ciphertext buffer. |
| /// |
| /// **mac** |
| /// |
| /// A pointer to destination mac buffer, typed as &mut [u8;16]. |
| /// |
| /// # Return value |
| /// |
| /// **SGX_SUCCESS** on success |
| /// |
| /// # Errors |
| /// |
| /// **SGX_ERROR_INVALID_PARAMETER** Indicates the parameter is invalid. |
| /// |
| /// **SGX_ERROR_UNEXPECTED** Indicates that encryption failed. |
| /// |
| /// # Requirements |
| /// |
| /// The caller should allocate the ciphertext buffer. This buffer should be |
| /// at least same length as plaintext buffer. The caller should allocate the |
| /// mac buffer, at least 16 bytes. |
| #[no_mangle] |
| pub extern "C" fn aes_gcm_128_encrypt(key: &[u8;16], |
| plaintext: *const u8, |
| text_len: usize, |
| iv: &[u8;12], |
| ciphertext: *mut u8, |
| mac: &mut [u8;16]) -> sgx_status_t { |
| |
| println!("aes_gcm_128_encrypt invoked!"); |
| |
| // First, we need slices for input |
| let plaintext_slice = unsafe { slice::from_raw_parts(plaintext, text_len) }; |
| |
| // Here we need to initiate the ciphertext buffer, though nothing in it. |
| // Thus show the length of ciphertext buffer is equal to plaintext buffer. |
| // If not, the length of ciphertext_vec will be 0, which leads to argument |
| // illegal. |
| let mut ciphertext_vec: Vec<u8> = vec![0; text_len]; |
| |
| // Second, for data with known length, we use array with fixed length. |
| // Here we cannot use slice::from_raw_parts because it provides &[u8] |
| // instead of &[u8,16]. |
| let aad_array: [u8; 0] = [0; 0]; |
| let mut mac_array: [u8; SGX_AESGCM_MAC_SIZE] = [0; SGX_AESGCM_MAC_SIZE]; |
| |
| // Always check the length after slice::from_raw_parts |
| if plaintext_slice.len() != text_len { |
| return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; |
| } |
| |
| let ciphertext_slice = &mut ciphertext_vec[..]; |
| println!("aes_gcm_128_encrypt parameter prepared! {}, {}", |
| plaintext_slice.len(), |
| ciphertext_slice.len()); |
| |
| // After everything has been set, call API |
| let result = rsgx_rijndael128GCM_encrypt(key, |
| &plaintext_slice, |
| iv, |
| &aad_array, |
| ciphertext_slice, |
| &mut mac_array); |
| println!("rsgx calling returned!"); |
| |
| // Match the result and copy result back to normal world. |
| match result { |
| Err(x) => { |
| return x; |
| } |
| Ok(()) => { |
| unsafe{ |
| ptr::copy_nonoverlapping(ciphertext_slice.as_ptr(), |
| ciphertext, |
| text_len); |
| } |
| *mac = mac_array; |
| } |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |
| |
| /// An AES-GCM-128 decrypt function sample. |
| /// |
| /// # Parameters |
| /// |
| /// **key** |
| /// |
| /// Key used in AES encryption, typed as &[u8;16]. |
| /// |
| /// **ciphertext** |
| /// |
| /// Cipher text to be encrypted. |
| /// |
| /// **text_len** |
| /// |
| /// Length of cipher text. |
| /// |
| /// **iv** |
| /// |
| /// Initialization vector of AES encryption, typed as &[u8;12]. |
| /// |
| /// **mac** |
| /// |
| /// A pointer to source mac buffer, typed as &[u8;16]. |
| /// |
| /// **plaintext** |
| /// |
| /// A pointer to destination plaintext buffer. |
| /// |
| /// # Return value |
| /// |
| /// **SGX_SUCCESS** on success |
| /// |
| /// # Errors |
| /// |
| /// **SGX_ERROR_INVALID_PARAMETER** Indicates the parameter is invalid. |
| /// |
| /// **SGX_ERROR_UNEXPECTED** means that decryption failed. |
| /// |
| /// # Requirements |
| // |
| /// The caller should allocate the plaintext buffer. This buffer should be |
| /// at least same length as ciphertext buffer. |
| #[no_mangle] |
| pub extern "C" fn aes_gcm_128_decrypt(key: &[u8;16], |
| ciphertext: *const u8, |
| text_len: usize, |
| iv: &[u8;12], |
| mac: &[u8;16], |
| plaintext: *mut u8) -> sgx_status_t { |
| |
| println!("aes_gcm_128_decrypt invoked!"); |
| |
| // First, for data with unknown length, we use vector as builder. |
| let ciphertext_slice = unsafe { slice::from_raw_parts(ciphertext, text_len) }; |
| let mut plaintext_vec: Vec<u8> = vec![0; text_len]; |
| |
| // Second, for data with known length, we use array with fixed length. |
| let aad_array: [u8; 0] = [0; 0]; |
| |
| if ciphertext_slice.len() != text_len { |
| return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; |
| } |
| |
| let plaintext_slice = &mut plaintext_vec[..]; |
| println!("aes_gcm_128_decrypt parameter prepared! {}, {}", |
| ciphertext_slice.len(), |
| plaintext_slice.len()); |
| |
| // After everything has been set, call API |
| let result = rsgx_rijndael128GCM_decrypt(key, |
| &ciphertext_slice, |
| iv, |
| &aad_array, |
| mac, |
| plaintext_slice); |
| |
| println!("rsgx calling returned!"); |
| |
| // Match the result and copy result back to normal world. |
| match result { |
| Err(x) => { |
| return x; |
| } |
| Ok(()) => { |
| unsafe { |
| ptr::copy_nonoverlapping(plaintext_slice.as_ptr(), |
| plaintext, |
| text_len); |
| } |
| } |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |
| |
| /// A sample aes-cmac function. |
| /// |
| /// # Parameters |
| /// |
| /// **text** |
| /// |
| /// The text message to be calculated. |
| /// |
| /// **text_len** |
| /// |
| /// An unsigned int indicate the length of input text message. |
| /// |
| /// **key** |
| /// |
| /// The key used in AES-CMAC, 16 bytes sized. |
| /// |
| /// **cmac** |
| /// |
| /// The output buffer, at least 16 bytes available. |
| /// |
| /// # Return value |
| /// |
| /// **SGX_SUCCESS** on success. |
| /// |
| /// # Errors |
| /// |
| /// **SGX_ERROR_INVALID_PARAMETER** indicates invalid input parameters |
| /// |
| /// # Requirement |
| /// |
| /// The caller should allocate the output cmac buffer. |
| #[no_mangle] |
| pub extern "C" fn aes_cmac(text: *const u8, |
| text_len: usize, |
| key: &[u8;16], |
| cmac: &mut [u8;16]) -> sgx_status_t { |
| |
| let text_slice = unsafe { slice::from_raw_parts(text, text_len) }; |
| |
| if text_slice.len() != text_len { |
| return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; |
| } |
| |
| let result = rsgx_rijndael128_cmac_slice(key, &text_slice); |
| |
| match result { |
| Err(x) => return x, |
| Ok(m) => *cmac = m |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |
| |
| |
| #[no_mangle] |
| pub extern "C" fn rsa_key(text: * const u8, text_len: usize) -> sgx_status_t { |
| |
| let text_slice = unsafe { slice::from_raw_parts(text, text_len) }; |
| |
| if text_slice.len() != text_len { |
| return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; |
| } |
| |
| let mod_size: i32 = 256; |
| let exp_size: i32 = 4; |
| let mut n: Vec<u8> = vec![0_u8; mod_size as usize]; |
| let mut d: Vec<u8> = vec![0_u8; mod_size as usize]; |
| let mut e: Vec<u8> = vec![1, 0, 1, 0]; |
| let mut p: Vec<u8> = vec![0_u8; mod_size as usize / 2]; |
| let mut q: Vec<u8> = vec![0_u8; mod_size as usize / 2]; |
| let mut dmp1: Vec<u8> = vec![0_u8; mod_size as usize / 2]; |
| let mut dmq1: Vec<u8> = vec![0_u8; mod_size as usize / 2]; |
| let mut iqmp: Vec<u8> = vec![0_u8; mod_size as usize / 2]; |
| |
| let result = rsgx_create_rsa_key_pair(mod_size, |
| exp_size, |
| n.as_mut_slice(), |
| d.as_mut_slice(), |
| e.as_mut_slice(), |
| p.as_mut_slice(), |
| q.as_mut_slice(), |
| dmp1.as_mut_slice(), |
| dmq1.as_mut_slice(), |
| iqmp.as_mut_slice()); |
| |
| match result { |
| Err(x) => { |
| return x; |
| }, |
| Ok(()) => {}, |
| } |
| |
| let privkey = SgxRsaPrivKey::new(); |
| let pubkey = SgxRsaPubKey::new(); |
| |
| let result = pubkey.create(mod_size, |
| exp_size, |
| n.as_slice(), |
| e.as_slice()); |
| match result { |
| Err(x) => return x, |
| Ok(()) => {}, |
| }; |
| |
| let result = privkey.create(mod_size, |
| exp_size, |
| e.as_slice(), |
| p.as_slice(), |
| q.as_slice(), |
| dmp1.as_slice(), |
| dmq1.as_slice(), |
| iqmp.as_slice()); |
| match result { |
| Err(x) => return x, |
| Ok(()) => {}, |
| }; |
| |
| let mut ciphertext: Vec<u8> = vec![0_u8; 256]; |
| let mut chipertext_len: usize = ciphertext.len(); |
| let ret = pubkey.encrypt_sha256(ciphertext.as_mut_slice(), |
| &mut chipertext_len, |
| text_slice); |
| match ret { |
| Err(x) => { |
| return x; |
| }, |
| Ok(()) => { |
| println!("rsa chipertext_len: {:?}", chipertext_len); |
| }, |
| }; |
| |
| let mut plaintext: Vec<u8> = vec![0_u8; 256]; |
| let mut plaintext_len: usize = plaintext.len(); |
| let ret = privkey.decrypt_sha256(plaintext.as_mut_slice(), |
| &mut plaintext_len, |
| ciphertext.as_slice()); |
| match ret { |
| Err(x) => { |
| return x; |
| }, |
| Ok(()) => { |
| println!("rsa plaintext_len: {:?}", plaintext_len); |
| }, |
| }; |
| |
| if plaintext[..plaintext_len].consttime_memeq(text_slice) == false { |
| return sgx_status_t::SGX_ERROR_UNEXPECTED; |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |