1: <?php
2:
3: /**
4: * Encryption with the libsodium extension
5: *
6: * This extends our standard encryption and will override it if libsodium is
7: * present. Checking a password and converting cipher text to clear text fall
8: * back to the standard Hm_Crypt library if they fail. This is to ensure
9: * backwards compatibility.
10: *
11: * @package framework
12: * @subpackage crypt
13: */
14:
15: class Hm_Crypt extends Hm_Crypt_Base {
16:
17: /**
18: * Convert ciphertext to plaintext
19: * @param string $string ciphertext to decrypt
20: * @param string $key encryption key
21: * @return string|false decrypted text
22: */
23: public static function plaintext($string, $key) {
24: if (!LIBSODIUM) {
25: return parent::plaintext($string, $key);
26: }
27: $res = false;
28: $raw_string = base64_decode($string);
29: if (!$raw_string || strlen($raw_string) < 60) {
30: return false;
31: }
32: list($salt, $crypt_key) = self::keygen($key, substr($raw_string, 0, 24));
33: $hmac = substr($raw_string, 24, 32);
34: $crypt_string = substr($raw_string, 56);
35:
36: if (Hm_Sodium_Compat::crypto_auth_verify($hmac, $crypt_string, $crypt_key)) {
37: $res = Hm_Sodium_Compat::crypto_secretbox_open($crypt_string, $salt, $crypt_key);
38: }
39: if ($res === false) {
40: return parent::plaintext($string, $key);
41: }
42: return $res;
43: }
44:
45: /**
46: * Convert plaintext into ciphertext
47: * @param string $string plaintext to encrypt
48: * @param string $key encryption key
49: * @return string encrypted text
50: */
51: public static function ciphertext($string, $key) {
52: if (!LIBSODIUM) {
53: return parent::ciphertext($string, $key);
54: }
55: list($salt, $key) = self::keygen($key);
56: $ciphertext = Hm_Sodium_Compat::crypto_secretbox($string, $salt, $key);
57: $mac = Hm_Sodium_Compat::crypto_auth($ciphertext, $key);
58: return base64_encode($salt.$mac.$ciphertext);
59: }
60:
61: /**
62: * Hash a password using libsodium. Args not defined here are for backwards
63: * compat usage with our built in crypto
64: * @param string $password password to hash
65: * @return string
66: */
67: public static function hash_password($password, $salt = false, $count = false, $algo = 'sha512', $type = 'php') {
68: if (!LIBSODIUM) {
69: return parent::hash_password($password, $salt, $count, $algo, $type);
70: }
71: return Hm_Sodium_Compat::crypto_pwhash_str($password);
72: }
73:
74: /**
75: * Check a password against it's stored hash using libsodium. If that
76: * fails, try our built in crypto otherwise updating to libsodium breaks
77: * everything
78: * @param string $password clear text password
79: * @param string $hash hashed password
80: * @return bool
81: */
82: public static function check_password($password, $hash) {
83: if (!LIBSODIUM) {
84: return parent::check_password($password, $hash);
85: }
86: if (!Hm_Sodium_Compat::crypto_pwhash_str_verify($hash, $password)) {
87: return parent::check_password($password, $hash);
88: }
89: return true;
90: }
91:
92: /**
93: * stretch (or shrink) a key for libsodium
94: * @param string $key the key to stretch/shrink
95: * @param string $salt a salt to use, or create one if needed
96: * @return string[]
97: */
98: protected static function keygen($key, $salt = false) {
99: if ($salt === false) {
100: $salt = Hm_Sodium_Compat::randombytes_buf();
101: }
102: return parent::keygen($key, $salt);
103: }
104: }
105: