| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CRYPTO_CIPHER_H_ |
| #define CRYPTO_CIPHER_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <zircon/types.h> |
| |
| #include <memory> |
| |
| #include <crypto/bytes.h> |
| #include <crypto/secret.h> |
| #include <fbl/macros.h> |
| |
| // |crypto::Cipher| is used to encrypt and decrypt data. Ciphers differ from AEADs in that they |
| // require block-aligned lengths and do not check data integrity. This implementation can be used |
| // as either a stream cipher, or as a random access cipher if the cipher has a "tweaked codebook |
| // mode". See the variants of |Init| and |Transform| for details. A 64 bit nonce is used to seal |
| // plain texts, meaning a given key and IV can be used for at most 2^64 - 1 operations. |
| namespace crypto { |
| |
| class __EXPORT Cipher final { |
| public: |
| // Algorithm enumerates the supported secret key ciphers. |
| enum Algorithm { |
| kUninitialized = 0, |
| kAES256_XTS, // A "tweaked cipher |
| }; |
| |
| // Indicates whether the objects turns plaintext into ciphertext or vice versa. |
| enum Direction { |
| kUnset = 0, |
| kEncrypt, |
| kDecrypt, |
| }; |
| |
| Cipher(); |
| ~Cipher(); |
| |
| Direction direction() const { return direction_; } |
| uint64_t alignment() const { return alignment_; } |
| |
| // Gets the number of bytes needed for the symmetric key used by the given |cipher|. |
| static zx_status_t GetKeyLen(Algorithm cipher, size_t* out); |
| |
| // Gets the number of bytes needed for the initialization vector (IV) used by the given |
| // |cipher|. |
| static zx_status_t GetIVLen(Algorithm cipher, size_t* out); |
| |
| // Gets the cipher block size in bytes for the given |cipher|. Data passed to |Encrypt| or |
| // |Decrypt| must be a multiple of this size. |
| static zx_status_t GetBlockSize(Algorithm cipher, size_t* out); |
| |
| // Sets up the cipher to encrypt or decrypt data using the given |key| and |iv|, based on the |
| // given |direction|, either as: |
| // - A stream ciphers, using the first variant that omits the |alignment|. |
| // - As a random access cipher, using the second variant. All offsets must be |
| // |alignment|-aligned, and |alignment| must be a power of 2. |
| zx_status_t Init(Algorithm algo, Direction direction, const Secret& key, const Bytes& iv, |
| uint64_t alignment); |
| |
| // Sets up the cipher to encrypt data using the given |key| and |iv|, either as a stream cipher |
| // or a random access cipher, as described above in |Init|. |
| zx_status_t InitEncrypt(Algorithm algo, const Secret& key, const Bytes& iv) { |
| return Init(algo, kEncrypt, key, iv, 0); |
| } |
| zx_status_t InitEncrypt(Algorithm algo, const Secret& key, const Bytes& iv, uint64_t alignment) { |
| return Init(algo, kEncrypt, key, iv, alignment); |
| } |
| |
| // Sets up the cipher to decrypt data using the given |key| and |iv|, either as a stream cipher |
| // or a random access cipher, as described above in |Init|. |
| zx_status_t InitDecrypt(Algorithm algo, const Secret& key, const Bytes& iv) { |
| return Init(algo, kDecrypt, key, iv, 0); |
| } |
| zx_status_t InitDecrypt(Algorithm algo, const Secret& key, const Bytes& iv, uint64_t alignment) { |
| return Init(algo, kDecrypt, key, iv, alignment); |
| } |
| |
| // Encrypts or decrypts |length| bytes from |in| to |out|, based on the given |direction| and |
| // the parameters set in |Init|: |
| // - Must have been configured with the same |direction|. |
| // - If |alignment| was non-zero, |offset| must be a multiple of it. |
| // Finally, |length| must be a multiple of cipher blocks, and |out| must have room for |length| |
| // bytes. This method will fail if called 2^64 or more times with the same key and IV. |
| zx_status_t Transform(const uint8_t* in, zx_off_t offset, size_t length, uint8_t* out, |
| Direction Direction); |
| |
| // Encrypts |len| bytes from |in| to |out|, as described above in |Transform|. |
| zx_status_t Encrypt(const uint8_t* in, size_t length, uint8_t* out) { |
| return Transform(in, 0, length, out, kEncrypt); |
| } |
| zx_status_t Encrypt(const uint8_t* in, zx_off_t offset, size_t length, uint8_t* out) { |
| return Transform(in, offset, length, out, kEncrypt); |
| } |
| |
| // Decrypts |len| bytes from |in| to |out|, as described above in |Transform|. |
| zx_status_t Decrypt(const uint8_t* in, size_t length, uint8_t* out) { |
| return Transform(in, 0, length, out, kDecrypt); |
| } |
| zx_status_t Decrypt(const uint8_t* in, zx_off_t offset, size_t length, uint8_t* out) { |
| return Transform(in, offset, length, out, kDecrypt); |
| } |
| |
| // Clears all state from this instance. |
| void Reset(); |
| |
| private: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(Cipher); |
| |
| // Opaque crypto implementation context. |
| struct Context; |
| |
| // Opaque pointer to the crypto implementation context. |
| std::unique_ptr<Context> ctx_; |
| // Indicates which algorithm to use to transform data. |
| Algorithm cipher_; |
| // Indicates whether configured to encrypt or decrypt. |
| Direction direction_; |
| // Cipher block size. |
| size_t block_size_; |
| // Buffer holding initial vector. The IV is expanded to be |zx_off_t|-aligned. |
| std::unique_ptr<zx_off_t[]> iv_; |
| // Original value of |iv_[0]|. |Transform| will fail if |iv_[0]| wraps around to this value. |
| zx_off_t iv0_; |
| // If non-zero, indicates how many bytes to use a nonce for before incrementing. |
| uint64_t alignment_; |
| }; |
| } // namespace crypto |
| |
| #endif // CRYPTO_CIPHER_H_ |