[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 namespace Defuse\Crypto; 4 5 use Defuse\Crypto\Exception as Ex; 6 7 final class Encoding 8 { 9 const CHECKSUM_BYTE_SIZE = 32; 10 const CHECKSUM_HASH_ALGO = 'sha256'; 11 const SERIALIZE_HEADER_BYTES = 4; 12 13 /** 14 * Converts a byte string to a hexadecimal string without leaking 15 * information through side channels. 16 * 17 * @param string $byte_string 18 * 19 * @throws Ex\EnvironmentIsBrokenException 20 * 21 * @return string 22 */ 23 public static function binToHex($byte_string) 24 { 25 $hex = ''; 26 $len = Core::ourStrlen($byte_string); 27 for ($i = 0; $i < $len; ++$i) { 28 $c = \ord($byte_string[$i]) & 0xf; 29 $b = \ord($byte_string[$i]) >> 4; 30 $hex .= \pack( 31 'CC', 32 87 + $b + ((($b - 10) >> 8) & ~38), 33 87 + $c + ((($c - 10) >> 8) & ~38) 34 ); 35 } 36 return $hex; 37 } 38 39 /** 40 * Converts a hexadecimal string into a byte string without leaking 41 * information through side channels. 42 * 43 * @param string $hex_string 44 * 45 * @throws Ex\BadFormatException 46 * @throws Ex\EnvironmentIsBrokenException 47 * 48 * @return string 49 * @psalm-suppress TypeDoesNotContainType 50 */ 51 public static function hexToBin($hex_string) 52 { 53 $hex_pos = 0; 54 $bin = ''; 55 $hex_len = Core::ourStrlen($hex_string); 56 $state = 0; 57 $c_acc = 0; 58 59 while ($hex_pos < $hex_len) { 60 $c = \ord($hex_string[$hex_pos]); 61 $c_num = $c ^ 48; 62 $c_num0 = ($c_num - 10) >> 8; 63 $c_alpha = ($c & ~32) - 55; 64 $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; 65 if (($c_num0 | $c_alpha0) === 0) { 66 throw new Ex\BadFormatException( 67 'Encoding::hexToBin() input is not a hex string.' 68 ); 69 } 70 $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); 71 if ($state === 0) { 72 $c_acc = $c_val * 16; 73 } else { 74 $bin .= \pack('C', $c_acc | $c_val); 75 } 76 $state ^= 1; 77 ++$hex_pos; 78 } 79 return $bin; 80 } 81 82 /** 83 * Remove trialing whitespace without table look-ups or branches. 84 * 85 * Calling this function may leak the length of the string as well as the 86 * number of trailing whitespace characters through side-channels. 87 * 88 * @param string $string 89 * @return string 90 */ 91 public static function trimTrailingWhitespace($string = '') 92 { 93 $length = Core::ourStrlen($string); 94 if ($length < 1) { 95 return ''; 96 } 97 do { 98 $prevLength = $length; 99 $last = $length - 1; 100 $chr = \ord($string[$last]); 101 102 /* Null Byte (0x00), a.k.a. \0 */ 103 // if ($chr === 0x00) $length -= 1; 104 $sub = (($chr - 1) >> 8 ) & 1; 105 $length -= $sub; 106 $last -= $sub; 107 108 /* Horizontal Tab (0x09) a.k.a. \t */ 109 $chr = \ord($string[$last]); 110 // if ($chr === 0x09) $length -= 1; 111 $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1; 112 $length -= $sub; 113 $last -= $sub; 114 115 /* New Line (0x0a), a.k.a. \n */ 116 $chr = \ord($string[$last]); 117 // if ($chr === 0x0a) $length -= 1; 118 $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1; 119 $length -= $sub; 120 $last -= $sub; 121 122 /* Carriage Return (0x0D), a.k.a. \r */ 123 $chr = \ord($string[$last]); 124 // if ($chr === 0x0d) $length -= 1; 125 $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1; 126 $length -= $sub; 127 $last -= $sub; 128 129 /* Space */ 130 $chr = \ord($string[$last]); 131 // if ($chr === 0x20) $length -= 1; 132 $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1; 133 $length -= $sub; 134 } while ($prevLength !== $length && $length > 0); 135 return (string) Core::ourSubstr($string, 0, $length); 136 } 137 138 /* 139 * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS: 140 * 141 * The checksum introduces a potential security weakness. For example, 142 * suppose we apply a checksum to a key, and that an adversary has an 143 * exploit against the process containing the key, such that they can 144 * overwrite an arbitrary byte of memory and then cause the checksum to 145 * be verified and learn the result. 146 * 147 * In this scenario, the adversary can extract the key one byte at 148 * a time by overwriting it with their guess of its value and then 149 * asking if the checksum matches. If it does, their guess was right. 150 * This kind of attack may be more easy to implement and more reliable 151 * than a remote code execution attack. 152 * 153 * This attack also applies to authenticated encryption as a whole, in 154 * the situation where the adversary can overwrite a byte of the key 155 * and then cause a valid ciphertext to be decrypted, and then 156 * determine whether the MAC check passed or failed. 157 * 158 * By using the full SHA256 hash instead of truncating it, I'm ensuring 159 * that both ways of going about the attack are equivalently difficult. 160 * A shorter checksum of say 32 bits might be more useful to the 161 * adversary as an oracle in case their writes are coarser grained. 162 * 163 * Because the scenario assumes a serious vulnerability, we don't try 164 * to prevent attacks of this style. 165 */ 166 167 /** 168 * INTERNAL USE ONLY: Applies a version header, applies a checksum, and 169 * then encodes a byte string into a range of printable ASCII characters. 170 * 171 * @param string $header 172 * @param string $bytes 173 * 174 * @throws Ex\EnvironmentIsBrokenException 175 * 176 * @return string 177 */ 178 public static function saveBytesToChecksummedAsciiSafeString($header, $bytes) 179 { 180 // Headers must be a constant length to prevent one type's header from 181 // being a prefix of another type's header, leading to ambiguity. 182 Core::ensureTrue( 183 Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES, 184 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' 185 ); 186 187 return Encoding::binToHex( 188 $header . 189 $bytes . 190 \hash( 191 self::CHECKSUM_HASH_ALGO, 192 $header . $bytes, 193 true 194 ) 195 ); 196 } 197 198 /** 199 * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns 200 * the encoded byte string. 201 * 202 * @param string $expected_header 203 * @param string $string 204 * 205 * @throws Ex\EnvironmentIsBrokenException 206 * @throws Ex\BadFormatException 207 * 208 * @return string 209 */ 210 public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string) 211 { 212 // Headers must be a constant length to prevent one type's header from 213 // being a prefix of another type's header, leading to ambiguity. 214 Core::ensureTrue( 215 Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES, 216 'Header must be 4 bytes.' 217 ); 218 219 /* If you get an exception here when attempting to load from a file, first pass your 220 key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */ 221 $bytes = Encoding::hexToBin($string); 222 223 /* Make sure we have enough bytes to get the version header and checksum. */ 224 if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) { 225 throw new Ex\BadFormatException( 226 'Encoded data is shorter than expected.' 227 ); 228 } 229 230 /* Grab the version header. */ 231 $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES); 232 233 if ($actual_header !== $expected_header) { 234 throw new Ex\BadFormatException( 235 'Invalid header.' 236 ); 237 } 238 239 /* Grab the bytes that are part of the checksum. */ 240 $checked_bytes = (string) Core::ourSubstr( 241 $bytes, 242 0, 243 Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE 244 ); 245 246 /* Grab the included checksum. */ 247 $checksum_a = (string) Core::ourSubstr( 248 $bytes, 249 Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, 250 self::CHECKSUM_BYTE_SIZE 251 ); 252 253 /* Re-compute the checksum. */ 254 $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true); 255 256 /* Check if the checksum matches. */ 257 if (! Core::hashEquals($checksum_a, $checksum_b)) { 258 throw new Ex\BadFormatException( 259 "Data is corrupted, the checksum doesn't match" 260 ); 261 } 262 263 return (string) Core::ourSubstr( 264 $bytes, 265 self::SERIALIZE_HEADER_BYTES, 266 Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE 267 ); 268 } 269 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |