Open starekrow opened 6 years ago
I think isolating the crypto and defaulting it to keep the package easy to use.
Let me know your thoughts, and I can work on implementing it
public function Lock( $message )
{
if (!$this->data) {
return false;
}
$cryptoLibrary = $this->getCryptoLibrary()
$ciphertext_raw = $cryptoLibrary->encrypt($message, $this->getEncryptionKey());
$hmac = $cryptoLibrary->generateHmac($ciphertext_raw, $this->getHmacKey());
$ciphertext = base64_encode($iv.$hmac.$ciphertext_raw);
return $ciphertext;
}
I was debating if the encryption interface should be separate from the hmac interface.
interface CryptoLibraryInterface
{
public function generateRandomBytes($length);
public function encrypt($message);
public function decrypt($message);
public function setEncryptionCipher($cipher);
public function getEncryptionCipher();
public function getEncryptionKeyLength();
public function getEncryptionKey();
public function setEncryptionKey($key);
public function generateHmac($message);
public function isHmacValid($hmac, $message);
public function setHmacAlgorithm($algo);
public function getHmacAlgorithm();
public function getHmacKeyLength();
public function getHmacKey();
public function setHmacKey($key);
}
abstract class AbstractCryptoLibrary implements CryptoLibraryInterface
{
private $hmacKey;
private $encryptionKey;
private $cipher;
public function setEncryptionCipher($cipher)
{
$this->cipher = $cipher;
}
public function getEncryptionCipher()
{
return $this->cipher;
}
public function setEncryptionKey($key)
{
$this->encryptionKey = $key;
}
public function getEncryptionKey()
{
if (isset($this->encryptionKey) === false) {
$keyLength = $this->getEncryptionKeyLength();
$key = $this->generateRandomBytes($keyLength);
$this->setEncryptionKey($key);
}
return $this->encryptionKey;
}
public function isHmacValid($hmac, $message) {
return $this->generateHmac($message) === $hmac;
}
//... rest of the common functions
}
class OpenSSLCryptoLibrary extends AbstractCryptoLibrary
{
public function generateRandomBytes($length)
{
return openssl_random_pseudo_bytes($length);
}
//... rest of the openssl specific functions
}
Hmm. I think it would work out better to move the abstraction deeper, along these lines:
public function hash( $alg, $data );
public function hmac( $alg, $key, $data );
public function hkdf( $alg, $ikm, $len, $salt, $info );
public function encrypt( $alg, $key, $iv, $data );
public function decrypt( $alg, $key, $iv, $data );
public function hashcmp( $h1, $h2 );
public function random( $count );
Just a couple of assumptions (always binary strings, no wierd operational modes) cleans up the interface a lot. This then becomes a useful and clean building block for any number of related problems. It also leaves all the decisions of what to do inside CryptoKey
instead of burying or splitting them.
Still need to work out how to handle algorithm names and discovery. It should be as permissive as possible without tolerating ambiguous input.
FYI all, I'm building this out now. I'm going with a static API and a driver model, should be pretty slick.
It would be nice to have optional support for libsodium as an alternative to the
openssl
extension, since libsodium is moving into core.This could be hacked in place, or done by isolating the crypto use in CryptoKey. Either way might complicate cipher selection (needs research).