/** * Break a public or private key down into its constituant components * * @access private * @see _convertPublicKey() * @see _convertPrivateKey() * @param String $key * @param Integer $type * @return Array */ function _parseKey($key, $type) { switch ($type) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: if (!is_array($key)) { return false; } $components = array(); switch (true) { case isset($key['e']): $components['publicExponent'] = $key['e']->copy(); break; case isset($key['exponent']): $components['publicExponent'] = $key['exponent']->copy(); break; case isset($key['publicExponent']): $components['publicExponent'] = $key['publicExponent']->copy(); break; case isset($key[0]): $components['publicExponent'] = $key[0]->copy(); } switch (true) { case isset($key['n']): $components['modulus'] = $key['n']->copy(); break; case isset($key['modulo']): $components['modulus'] = $key['modulo']->copy(); break; case isset($key['modulus']): $components['modulus'] = $key['modulus']->copy(); break; case isset($key[1]): $components['modulus'] = $key[1]->copy(); } return $components; case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: http://tools.ietf.org/html/rfc1421#section-4.6.1.1 http://tools.ietf.org/html/rfc1421#section-4.6.1.3 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's own implementation. ie. the implementation *is* the standard and any bugs that may exist in that implementation are part of the standard, as well. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ if (preg_match('#DEK-Info: DES-EDE3-CBC,(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[1])); $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key $symkey .= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); $ciphertext = base64_decode(preg_replace('#.+(\\r|\\n|\\r\\n)\\1|[\\r\\n]|-.+-#s', '', $key)); if ($ciphertext === false) { return false; } if (!class_exists('Crypt_TripleDES')) { require_once 'Crypt/TripleDES.php'; } $des = new Crypt_TripleDES(); $des->setKey($symkey); $des->setIV($iv); $key = $des->decrypt($ciphertext); } else { $key = base64_decode(preg_replace('#-.+-|[\\r\\n]#', '', $key)); if ($key === false) { return false; } } $private = false; $components = array(); $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_SEQUENCE $this->_decodeLength($key); // skip over the length of the above sequence $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER $length = $this->_decodeLength($key); $temp = $this->_string_shift($key, $length); if (strlen($temp) != 1 || ord($temp) > 2) { $components['modulus'] = new Math_BigInteger($temp, -256); $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER $length = $this->_decodeLength($key); $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); return $components; } $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER $length = $this->_decodeLength($key); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256)); if (!empty($key)) { $key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE $this->_decodeLength($key); while (!empty($key)) { $key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE $this->_decodeLength($key); $key = substr($key, 1); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); } } return $components; case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); if ($key === false) { return false; } $components = array(); extract(unpack('Nlength', $this->_string_shift($key, 4))); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256); extract(unpack('Nlength', $this->_string_shift($key, 4))); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); return $components; } }
/** * 3-DES Decrypt in EDE-CBC3 Mode * * @param string $hexEncryptedData * Encrypted Data in hexadecimal representation * @param string $hexKey * Key in hexadecimal representation * @param bool $useDesModeCBC3 * Use DES CBC3 Mode * * @return string * Decrypted data in hexadecimal representation */ public static function tripleDesDecrypt($hexEncryptedData, $hexKey, $useDesModeCBC3 = false) { //fix Crypt Library padding $hexKey = $hexKey . substr($hexKey, 0, 16); if ($useDesModeCBC3) { $crypt3DES = new \Crypt_TripleDES(CRYPT_DES_MODE_CBC3); // IDTech uses mode CRYPT_DES_MODE_CBC3 } else { $crypt3DES = new \Crypt_TripleDES(CRYPT_DES_MODE_ECB); // Chinese uses mode CRYPT_DES_MODE_ECB } $crypt3DES->setKey(Utility::hex2bin($hexKey)); $crypt3DES->disablePadding(); return strtoupper(bin2hex($crypt3DES->decrypt(Utility::hex2bin($hexEncryptedData)))); }