blob: 4a34986a876c76b6163f244e72a763b6b15fd390 [file] [log] [blame]
// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Crypto - class for handling the keyset key management functions relating to
// cryptohome. This includes wrapping/unwrapping the vault keyset (and
// supporting functions) and setting/clearing the user keyring for use with
// ecryptfs.
#ifndef CRYPTOHOME_CRYPTO_H_
#define CRYPTOHOME_CRYPTO_H_
#include <base/basictypes.h>
#include <base/file_path.h>
#include "secure_blob.h"
#include "tpm.h"
#include "vault_keyset.h"
#include "vault_keyset.pb.h"
namespace cryptohome {
// Default number of hash rounds to use when generating key from a password
extern const unsigned int kDefaultPasswordRounds;
class Crypto : public EntropySource {
public:
// PaddingScheme dictates the padding at the end of the ciphertext:
// kPaddingNone - Do not use padding. The input plaintext must be a
// multiple of the crypto algorithm's block size. This is used in the
// encryption of the vault keyset as described in the Protection
// Mechanisms section of the README file.
// kPaddingLibraryDefault - Use OpenSSL default padding (PKCS#5), which
// allows the plaintext to be marginally verified on decrypt, and
// automatically handles plaintext that is not a multiple of the block
// size.
// kPaddingCryptohomeDefault - The default padding, which adds a SHA1 hash
// to the end of the plaintext before encryption so that the contents can
// be verified.
enum PaddingScheme {
kPaddingNone = 0,
kPaddingLibraryDefault = 1,
kPaddingCryptohomeDefault = 2,
};
enum BlockMode {
kEcb = 1,
kCbc = 2,
};
enum CryptoError {
CE_NONE = 0,
CE_TPM_FATAL,
CE_TPM_COMM_ERROR,
CE_TPM_DEFEND_LOCK,
CE_TPM_CRYPTO,
CE_SCRYPT_CRYPTO,
CE_OTHER_FATAL,
CE_OTHER_CRYPTO,
CE_NO_PUBLIC_KEY_HASH,
};
// Default constructor
Crypto();
virtual ~Crypto();
// Initializes Crypto
bool Init();
// Returns random bytes of the given length using OpenSSL's random number
// generator. The random number generator is automatically seeded from
// /dev/urandom by OpenSSL.
//
// Parameters
// rand (OUT) - Where to store the random bytes
// length - The number of random bytes to store in rand
void GetSecureRandom(unsigned char* rand, unsigned int length) const;
// Gets the AES block size
unsigned int GetAesBlockSize() const;
// AES decrypts the wrapped blob
//
// Parameters
// wrapped - The blob containing the encrypted data
// start - The position in the blob to start with
// count - The count of bytes to decrypt
// key - The AES key to use in decryption
// iv - The initialization vector to use
// padding - The padding method to use
// unwrapped (OUT) - The unwrapped (decrypted) data
bool AesDecrypt(const chromeos::Blob& wrapped, unsigned int start,
unsigned int count, const SecureBlob& key,
const SecureBlob& iv, PaddingScheme padding,
SecureBlob* unwrapped) const;
// AES encrypts the plain text data using the specified key
//
// Parameters
// unwrapped - The plain text data to encrypt
// start - The position in the blob to start with
// count - The count of bytes to encrypt
// key - The AES key to use
// iv - The initialization vector to use
// padding - The padding method to use
// wrapped - On success, the encrypted data
bool AesEncrypt(const chromeos::Blob& unwrapped, unsigned int start,
unsigned int count, const SecureBlob& key,
const SecureBlob& iv, PaddingScheme padding,
SecureBlob* wrapped) const;
// Same as AesDecrypt, but allows using either CBC or ECB
bool AesDecryptSpecifyBlockMode(const chromeos::Blob& wrapped,
unsigned int start, unsigned int count,
const SecureBlob& key, const SecureBlob& iv,
PaddingScheme padding, BlockMode block_mode,
SecureBlob* unwrapped) const;
// Same as AesEncrypt, but allows using either CBC or ECB
bool AesEncryptSpecifyBlockMode(const chromeos::Blob& unwrapped,
unsigned int start, unsigned int count,
const SecureBlob& key, const SecureBlob& iv,
PaddingScheme padding, BlockMode block_mode,
SecureBlob* wrapped) const;
// Creates a new RSA key
//
// Parameters
// key_bits - The key size to generate
// n (OUT) - the modulus
// p (OUT) - the private key
bool CreateRsaKey(unsigned int key_bits, SecureBlob* n, SecureBlob* p) const;
// Decrypts an encrypted vault keyset. The vault keyset should be the output
// of EncryptVaultKeyset().
//
// Parameters
// encrypted_keyset - The blob containing the encrypted keyset
// vault_key - The passkey used to decrypt the keyset
// crypt_flags (OUT) - Whether the keyset was wrapped by the TPM or scrypt
// error (OUT) - The specific error code on failure
// vault_keyset (OUT) - The decrypted vault keyset on success
bool DecryptVaultKeyset(const SerializedVaultKeyset& serialized,
const chromeos::Blob& vault_key,
unsigned int* crypt_flags, CryptoError* error,
VaultKeyset* vault_keyset) const;
// Encrypts the vault keyset with the given passkey
//
// Parameters
// vault_keyset - The VaultKeyset to encrypt
// vault_key - The passkey used to encrypt the keyset
// vault_key_salt - The salt to use for the vault passkey to key conversion
// when encrypting the keyset
// encrypted_keyset - On success, the encrypted vault keyset
bool EncryptVaultKeyset(const VaultKeyset& vault_keyset,
const SecureBlob& vault_key,
const SecureBlob& vault_key_salt,
SerializedVaultKeyset* serialized) const;
// Decrypts an encrypted vault keyset in the old method
//
// Parameters
// encrypted_keyset - The blob containing the encrypted keyset
// vault_key - The passkey used to decrypt the keyset
// vault_keyset (OUT) - The decrypted vault keyset on success
bool DecryptVaultKeysetOld(const chromeos::Blob& encrypted_keyset,
const chromeos::Blob& vault_key,
VaultKeyset* vault_keyset) const;
// Encrypts the vault keyset with the given passkey in the old method
//
// Parameters
// vault_keyset - The VaultKeyset to encrypt
// vault_key - The passkey used to wrap the keyset
// vault_key_salt - The salt to use for the vault passke to key conversion
// when encrypting the keyset
// encrypted_keyset - On success, the encrypted vault keyset
bool EncryptVaultKeysetOld(const VaultKeyset& vault_keyset,
const SecureBlob& vault_key,
const SecureBlob& vault_key_salt,
SecureBlob* encrypted_keyset) const;
// Converts the passkey directly to an AES key. This method derives the key
// using the default OpenSSL conversion method.
//
// Parameters
// passkey - The passkey (hash, currently) to create the key from
// salt - The salt used in creating the key
// rounds - The number of SHA rounds to perform
// key (OUT) - The AES key
// iv (OUT) - The initialization vector
bool PasskeyToAesKey(const chromeos::Blob& passkey,
const chromeos::Blob& salt, unsigned int rounds,
SecureBlob* key, SecureBlob* iv) const;
// Converts the passkey to a symmetric key used to decrypt the user's
// cryptohome key. This method calculates a SHA1 hash of the salt and the
// specified number of iterations on the passkey.
//
// Parameters
// passkey - The passkey (hash, currently) to create the key from
// salt - The salt used in creating the key
// iters - The hash iterations to use in generating the key
// wrapper (OUT) - The wrapper
void PasskeyToKeysetKey(const chromeos::Blob& passkey,
const chromeos::Blob& salt, unsigned int iters,
SecureBlob* key) const;
// Gets an existing salt, or creates one if it doesn't exist
//
// Parameters
// path - The path to the salt file
// length - The length of the new salt if it needs to be created
// force - If true, forces creation of a new salt even if the file exists
// salt (OUT) - The salt
bool GetOrCreateSalt(const FilePath& path, unsigned int length, bool force,
SecureBlob* salt) const;
// Adds the specified key to the ecryptfs keyring so that the cryptohome can
// be mounted. Clears the user keyring first.
//
// Parameters
// vault_keyset - The keyset to add
// key_signature (OUT) - The signature of the cryptohome key that should be
// used in subsequent calls to mount(2)
// filename_key_signature (OUT) - The signature of the cryptohome filename
// encryption key that should be used in subsequent calls to mount(2)
bool AddKeyset(const VaultKeyset& vault_keyset,
std::string* key_signature,
std::string* filename_key_signature) const;
// Clears the user's kernel keyring
void ClearKeyset() const;
// Gets the SHA1 hash of the data provided
void GetSha1(const chromeos::Blob& data, unsigned int start,
unsigned int count, SecureBlob* hash) const;
// Gets the SHA256 hash of the data provided
void GetSha256(const chromeos::Blob& data, unsigned int start,
unsigned int count, SecureBlob* hash) const;
// Encodes a binary blob to hex-ascii
//
// Parameters
// blob - The binary blob to convert
// buffer (IN/OUT) - Where to store the converted blob
// buffer_length - The size of the buffer
static void AsciiEncodeToBuffer(const chromeos::Blob& blob, char* buffer,
unsigned int buffer_length);
// Converts a null-terminated password to a passkey (ascii-encoded first half
// of the salted SHA1 hash of the password).
//
// Parameters
// password - The password to convert
// salt - The salt used during hashing
// passkey (OUT) - The passkey
static void PasswordToPasskey(const char* password,
const chromeos::Blob& salt,
SecureBlob* passkey);
// Ensures that the TPM is connected
CryptoError EnsureTpm(bool disconnect_first) const;
// Sets whether or not to use scrypt to add a layer of protection to the vault
// keyset when the TPM is not used
void set_fallback_to_scrypt(bool value) {
fallback_to_scrypt_ = value;
}
// Sets whether or not to use the TPM (must be called before init, depends
// on the presence of a functioning, initialized TPM). The TPM is merely used
// to add a layer of difficulty in a brute-force attack against the user's
// credentials.
void set_use_tpm(bool value) {
use_tpm_ = value;
}
// Sets whether to always load the TPM, even if it isn't used
void set_load_tpm(bool value) {
load_tpm_ = value;
}
// Sets the TPM implementation
void set_tpm(Tpm* value) {
tpm_ = value;
}
// Gets whether the TPM is set
bool has_tpm() {
return (tpm_ != NULL);
}
// Gets the TPM implementation
const Tpm* get_tpm() {
return tpm_;
}
// Checks if the TPM is connected
bool is_tpm_connected() {
if (tpm_ == NULL) {
return false;
}
return tpm_->IsConnected();
}
private:
// Converts a TPM error to a Crypto error
CryptoError TpmErrorToCrypto(Tpm::TpmRetryAction retry_action) const;
// Adds the specified key to the user keyring
//
// Parameters
// key - The key to add
// key_sig - The key's (ascii) signature
// salt - The salt
bool PushVaultKey(const SecureBlob& key, const std::string& key_sig,
const SecureBlob& salt) const;
// If set, the TPM will be used during the encryption of the vault keyset
bool use_tpm_;
// TODO(fes): Remove this when TPM becomes default or not, it is only used in
// keyset migration.
// If set, Crypto can process TPM-encrypted keysets, but won't default to save
// keysets as TPM-encrypted.
bool load_tpm_;
// The TPM implementation
Tpm* tpm_;
// If set, Crypto will use scrypt to protect the vault keyset when the TPM is
// not available for use (or turned off)
bool fallback_to_scrypt_;
DISALLOW_COPY_AND_ASSIGN(Crypto);
};
} // namespace cryptohome
#endif // CRYPTOHOME_CRYPTO_H_