1<?php 2/** 3 * PrivateBin 4 * 5 * a zero-knowledge paste bin 6 * 7 * @link https://github.com/PrivateBin/PrivateBin 8 * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) 9 * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License 10 * @version 1.3.5 11 */ 12 13namespace PrivateBin; 14 15/** 16 * FormatV2 17 * 18 * Provides validation function for version 2 format of pastes & comments. 19 */ 20class FormatV2 21{ 22 /** 23 * version 2 format validator 24 * 25 * Checks if the given array is a proper version 2 formatted, encrypted message. 26 * 27 * @access public 28 * @static 29 * @param array $message 30 * @param bool $isComment 31 * @return bool 32 */ 33 public static function isValid($message, $isComment = false) 34 { 35 $required_keys = array('adata', 'v', 'ct'); 36 if ($isComment) { 37 $required_keys[] = 'pasteid'; 38 $required_keys[] = 'parentid'; 39 } else { 40 $required_keys[] = 'meta'; 41 } 42 43 // Make sure no additionnal keys were added. 44 if (count(array_keys($message)) != count($required_keys)) { 45 return false; 46 } 47 48 // Make sure required fields are present. 49 foreach ($required_keys as $k) { 50 if (!array_key_exists($k, $message)) { 51 return false; 52 } 53 } 54 55 $cipherParams = $isComment ? $message['adata'] : $message['adata'][0]; 56 57 // Make sure some fields are base64 data: 58 // - initialization vector 59 if (!base64_decode($cipherParams[0], true)) { 60 return false; 61 } 62 // - salt 63 if (!base64_decode($cipherParams[1], true)) { 64 return false; 65 } 66 // - cipher text 67 if (!($ct = base64_decode($message['ct'], true))) { 68 return false; 69 } 70 71 // Make sure some fields have a reasonable size: 72 // - initialization vector 73 if (strlen($cipherParams[0]) > 24) { 74 return false; 75 } 76 // - salt 77 if (strlen($cipherParams[1]) > 14) { 78 return false; 79 } 80 81 // Make sure some fields contain no unsupported values: 82 // - version 83 if (!(is_int($message['v']) || is_float($message['v'])) || (float) $message['v'] < 2) { 84 return false; 85 } 86 // - iterations, refuse less then 10000 iterations (minimum NIST recommendation) 87 if (!is_int($cipherParams[2]) || $cipherParams[2] <= 10000) { 88 return false; 89 } 90 // - key size 91 if (!in_array($cipherParams[3], array(128, 192, 256), true)) { 92 return false; 93 } 94 // - tag size 95 if (!in_array($cipherParams[4], array(64, 96, 128), true)) { 96 return false; 97 } 98 // - algorithm, must be AES 99 if ($cipherParams[5] !== 'aes') { 100 return false; 101 } 102 // - mode 103 if (!in_array($cipherParams[6], array('ctr', 'cbc', 'gcm'), true)) { 104 return false; 105 } 106 // - compression 107 if (!in_array($cipherParams[7], array('zlib', 'none'), true)) { 108 return false; 109 } 110 111 // Reject data if entropy is too low 112 if (strlen($ct) > strlen(gzdeflate($ct))) { 113 return false; 114 } 115 116 // require only the key 'expire' in the metadata of pastes 117 if (!$isComment && ( 118 count($message['meta']) === 0 || 119 !array_key_exists('expire', $message['meta']) || 120 count($message['meta']) > 1 121 )) { 122 return false; 123 } 124 125 return true; 126 } 127} 128