DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
{@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
static public decodeLength ( string &$string ) : integer | ||
$string | string | |
리턴 | integer |
/** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ static function load($key, $password = '') { if (!is_string($key)) { return false; } $components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false); /* 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: (.+),(.+)#', $key, $matches)) { $iv = Hex::decode(trim($matches[2])); // remove the Proc-Type / DEK-Info sections as they're no longer needed $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key); $ciphertext = self::_extractBER($key); if ($ciphertext === false) { $ciphertext = $key; } $crypto = self::getEncryptionObject($matches[1]); $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3)); $crypto->setIV($iv); $key = $crypto->decrypt($ciphertext); if ($key === false) { return false; } } else { if (self::$format != self::MODE_DER) { $decoded = self::_extractBER($key); if ($decoded !== false) { $key = $decoded; } elseif (self::$format == self::MODE_PEM) { return false; } } } if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) { return false; } if (ASN1::decodeLength($key) != strlen($key)) { return false; } $tag = ord(Strings::shift($key)); /* intended for keys for which OpenSSL's asn1parse returns the following: 0:d=0 hl=4 l= 631 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=2 l= 13 cons: SEQUENCE 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 20:d=2 hl=2 l= 0 prim: NULL 22:d=1 hl=4 l= 609 prim: OCTET STRING ie. PKCS8 keys */ if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "0") { Strings::shift($key, 3); $tag = self::ASN1_SEQUENCE; } if ($tag == self::ASN1_SEQUENCE) { $temp = Strings::shift($key, ASN1::decodeLength($key)); if (ord(Strings::shift($temp)) != self::ASN1_OBJECT) { return false; } $length = ASN1::decodeLength($temp); switch (Strings::shift($temp, $length)) { case "*†H†÷\r": // rsaEncryption break; case "*†H†÷\r": // pbeWithMD5AndDES-CBC /* PBEParameter ::= SEQUENCE { salt OCTET STRING (SIZE(8)), iterationCount INTEGER } */ if (ord(Strings::shift($temp)) != self::ASN1_SEQUENCE) { return false; } if (ASN1::decodeLength($temp) != strlen($temp)) { return false; } Strings::shift($temp); // assume it's an octet string $salt = Strings::shift($temp, ASN1::decodeLength($temp)); if (ord(Strings::shift($temp)) != self::ASN1_INTEGER) { return false; } ASN1::decodeLength($temp); list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT)); Strings::shift($key); // assume it's an octet string $length = ASN1::decodeLength($key); if (strlen($key) != $length) { return false; } $crypto = new DES(DES::MODE_CBC); $crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount); $key = $crypto->decrypt($key); if ($key === false) { return false; } return self::load($key); default: return false; } /* intended for keys for which OpenSSL's asn1parse returns the following: 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING */ $tag = ord(Strings::shift($key)); // skip over the BIT STRING / OCTET STRING tag ASN1::decodeLength($key); // skip over the BIT STRING / OCTET STRING length // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of // unused bits in the final subsequent octet. The number shall be in the range zero to seven." // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2) if ($tag == self::ASN1_BITSTRING) { Strings::shift($key); } if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) { return false; } if (ASN1::decodeLength($key) != strlen($key)) { return false; } $tag = ord(Strings::shift($key)); } if ($tag != self::ASN1_INTEGER) { return false; } $length = ASN1::decodeLength($key); $temp = Strings::shift($key, $length); if (strlen($temp) != 1 || ord($temp) > 2) { $components['modulus'] = new BigInteger($temp, 256); Strings::shift($key); // skip over self::ASN1_INTEGER $length = ASN1::decodeLength($key); $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(Strings::shift($key, $length), 256); return $components; } if (ord(Strings::shift($key)) != self::ASN1_INTEGER) { return false; } $length = ASN1::decodeLength($key); $components['modulus'] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['publicExponent'] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['privateExponent'] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['primes'] = array(1 => new BigInteger(Strings::shift($key, $length), 256)); Strings::shift($key); $length = ASN1::decodeLength($key); $components['primes'][] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['exponents'] = array(1 => new BigInteger(Strings::shift($key, $length), 256)); Strings::shift($key); $length = ASN1::decodeLength($key); $components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['coefficients'] = array(2 => new BigInteger(Strings::shift($key, $length), 256)); if (!empty($key)) { if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) { return false; } ASN1::decodeLength($key); while (!empty($key)) { if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) { return false; } ASN1::decodeLength($key); $key = substr($key, 1); $length = ASN1::decodeLength($key); $components['primes'][] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256); Strings::shift($key); $length = ASN1::decodeLength($key); $components['coefficients'][] = new BigInteger(Strings::shift($key, $length), 256); } } return $components; }