fuchsia / fuchsia / refs/heads/releases/field-image-dogfood / . / zircon / system / ulib / zircon-crypto / include / crypto / cipher.h

// 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_ |