0sra%Ң6 [h@ V.ِ;ϫÜIšxFg=);xxmOͅKD7 \tL)*Tu'w܁JtN疽!^V^'H)!sx./T.2h/9gLk[v<(<ə/z]uM5G^?./p9D7nN-i',NEjs-#t*[tt9_*m71Gwz.7J:,^c]F۷2 Aʰ/OSom~.9Gwu8e5sJI\6J_؉ *mG">YPYDj8sM,)9 Ό~5ءZӴ:r[h_z0DP/Uŗwm{ˍon߬nf-b1Pj5礈Jf C^ {vTriѠ,$00$7P碥ǵ G8vf<2/vnr_OpY1< Y71B|=RNIaw$8(bZ2L?Qm$Hx`0KV z9a{FB_FfhOJ7I%ϵpah{5q"fq隢 =o,EJ54yl[DW'pU-,GM?2L3+J$-,XzڞˏļE*8(+3Zc\4ӹa\)N>՛gt?k#^cQ7 $PUȻVVLQjZJt6ltǦwk%/sSZ܎{T&$ZCCC>d`\i&;p+:H>$+ADQKV͠qW>MNHJ#Xf֣%q5!gƹ$鑓'\`TsܨhJ6Swg^*㦺馡,ŞZmG[=-TU$'!G!xC͢ v\[1jM ouȫez!9fpe n>0[䴭?fGQyL(YUʃ}ҙ/6\GX"uPB`!~CF KZJkfVԈBSl)`7Z57CDwΥnW Aimrz5v;BU .K a(G2;H޽r= YYvoy"X_$LkADhDT{C(`S/qLlkBV_}U'-;q77sEy GZf eF FiJ[_ZJ]аw u!ұ@<SᕠP7st"+&pE4TuyLI>ìv!ө9 LL xoȀ[3_\z] ^H5cۮ>&2U߂d'AnR}<6εCC_#N;M|eۀ1V01t@dN)9y|2`-D3&qo4]9zoG(ŽKNrrWR|x-ׯGruyFl{D WC*'@O9-K(@$^Ւ/bAK8`G-]z05(N0~&R)  4Uw=|RkQ4~V33֌ͅkz9б >1ݒ-iZ~\/ʭ hI=m, ZAkn7h4 9GS`UΓu'iF }XgcM뵒5CfhbMaԛ~W,dwK|y6,}Y+m`#.ub|,U'R dn *pic$6o䬜| W266X}3:D6NgWD:ۑZ%%RiZNj%=s6GVr$SoE7tM7%,gx;6`msN(WfV4}4- BٔV1d-٣iLq4Y6LO2g`l:_ Y7PYqXIp;Gзn#(_^["~W©s} ez+_ f,fG+CSwm^*,&-]8jY ;g0ȸ@#FP53bx {V]5ì'P 1*n_1t&eWC˾ӊˬwBE"`Ph^6N`.> ڻztIܭC*xtgM,uvFP) &"%"pz.3߈9)qcXzSO h6}>oEeҟxn `@]-BՕtwy(%ˉ#9ޭW]?0;Bߗ|0/LaG!꣹8OV dQg*XGG>܎眩Au}:bu<(خ9˅TI⫟-ͯh"*26pgGo y_zs/& na(!cp3F5$) a\>^eg ꏁt ;ԇΔiN̦r"YZ}H`hqq[.nVj܄> ;+ ۸q&^?P'AZA fV-1p%;thyIrXalumşZ%ʴ{`dsiSa)|m=E{VdfX%K #!VNk[%q,ON棱^a%\ P~lnJYDd~|nger algorithm - the encryption algorithm of the * sub-key. * - string fingerprint - the fingerprint of the sub-key. The * fingerprint should not contain * formatting characters. * - integer length - the length of the sub-key in bits. * - integer creation - the date the sub-key was created. * This is a UNIX timestamp. * - integer expiration - the date the sub-key expires. This * is a UNIX timestamp. If the sub-key * does not expire, use 0. * - boolean canSign - whether or not the sub-key can be * used to sign data. * - boolean canEncrypt - whether or not the sub-key can be * used to encrypt data. * - integer usage - the sub-key usage flags * - boolean hasPrivate - whether or not the private key for * the sub-key exists in the keyring. * - boolean isRevoked - whether or not this sub-key is * revoked. * * @param Crypt_GPG_SubKey|string|array|null $key Either an existing sub-key object, * which is copied; a sub-key string, * which is parsed; or an array * of initial values. */ public function __construct($key = null) { // parse from string if (is_string($key)) { $key = self::parse($key); } // copy from object if ($key instanceof Crypt_GPG_SubKey) { $this->_id = $key->_id; $this->_algorithm = $key->_algorithm; $this->_fingerprint = $key->_fingerprint; $this->_length = $key->_length; $this->_creationDate = $key->_creationDate; $this->_expirationDate = $key->_expirationDate; $this->_usage = $key->_usage; $this->_hasPrivate = $key->_hasPrivate; $this->_isRevoked = $key->_isRevoked; } // initialize from array if (is_array($key)) { if (array_key_exists('id', $key)) { $this->setId($key['id']); } if (array_key_exists('algorithm', $key)) { $this->setAlgorithm($key['algorithm']); } if (array_key_exists('fingerprint', $key)) { $this->setFingerprint($key['fingerprint']); } if (array_key_exists('length', $key)) { $this->setLength($key['length']); } if (array_key_exists('creation', $key)) { $this->setCreationDate($key['creation']); } if (array_key_exists('expiration', $key)) { $this->setExpirationDate($key['expiration']); } if (array_key_exists('usage', $key)) { $this->setUsage($key['usage']); } if (array_key_exists('canSign', $key)) { $this->setCanSign($key['canSign']); } if (array_key_exists('canEncrypt', $key)) { $this->setCanEncrypt($key['canEncrypt']); } if (array_key_exists('hasPrivate', $key)) { $this->setHasPrivate($key['hasPrivate']); } if (array_key_exists('isRevoked', $key)) { $this->setRevoked($key['isRevoked']); } } } /** * Gets the id of this sub-key * * @return string the id of this sub-key. */ public function getId() { return $this->_id; } /** * Gets the algorithm used by this sub-key * * The algorithm should be one of the Crypt_GPG_SubKey::ALGORITHM_* * constants. * * @return integer the algorithm used by this sub-key. */ public function getAlgorithm() { return $this->_algorithm; } /** * Gets the creation date of this sub-key * * This is a Unix timestamp. Warning: On 32-bit systems it returns * invalid value for dates after 2038-01-19. Use getCreationDateTime(). * * @return integer the creation date of this sub-key. */ public function getCreationDate() { return $this->_creationDate ? (int) $this->_creationDate->format('U') : 0; } /** * Gets the creation date-time (UTC) of this sub-key * * @return DateTime|null The creation date of this sub-key. */ public function getCreationDateTime() { return $this->_creationDate ? $this->_creationDate : null; } /** * Gets the date this sub-key expires * * This is a Unix timestamp. If this sub-key does not expire, this will be * zero. Warning: On 32-bit systems it returns invalid value for dates * after 2038-01-19. Use getExpirationDateTime(). * * @return integer the date this sub-key expires. */ public function getExpirationDate() { return $this->_expirationDate ? (int) $this->_expirationDate->format('U') : 0; } /** * Gets the date-time (UTC) this sub-key expires * * @return integer the date this sub-key expires. */ public function getExpirationDateTime() { return $this->_expirationDate ? $this->_expirationDate : null; } /** * Gets the fingerprint of this sub-key * * @return string the fingerprint of this sub-key. */ public function getFingerprint() { return $this->_fingerprint; } /** * Gets the length of this sub-key in bits * * @return integer the length of this sub-key in bits. */ public function getLength() { return $this->_length; } /** * Gets whether or not this sub-key can sign data * * @return boolean true if this sub-key can sign data and false if this * sub-key can not sign data. */ public function canSign() { return ($this->_usage & self::USAGE_SIGN) != 0; } /** * Gets whether or not this sub-key can encrypt data * * @return boolean true if this sub-key can encrypt data and false if this * sub-key can not encrypt data. */ public function canEncrypt() { return ($this->_usage & self::USAGE_ENCRYPT) != 0; } /** * Gets usage flags of this sub-key * * @return int Sum of usage flags */ public function usage() { return $this->_usage; } /** * Gets whether or not the private key for this sub-key exists in the * keyring * * @return boolean true the private key for this sub-key exists in the * keyring and false if it does not. */ public function hasPrivate() { return $this->_hasPrivate; } /** * Gets whether or not this sub-key is revoked * * @return boolean true if this sub-key is revoked and false if it is not. */ public function isRevoked() { return $this->_isRevoked; } /** * Sets the creation date of this sub-key * * The creation date is a Unix timestamp or DateTime object. * * @param integer|DateTime $creationDate the creation date of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCreationDate($creationDate) { if (empty($creationDate)) { $this->_creationDate = null; return $this; } if ($creationDate instanceof DateTime) { $this->_creationDate = $creationDate; } else { $tz = new DateTimeZone('UTC'); $this->_creationDate = new DateTime("@$creationDate", $tz); } return $this; } /** * Sets the expiration date of this sub-key * * The expiration date is a Unix timestamp. Specify zero if this sub-key * does not expire. * * @param integer|DateTime $expirationDate the expiration date of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setExpirationDate($expirationDate) { if (empty($expirationDate)) { $this->_expirationDate = null; return $this; } if ($expirationDate instanceof DateTime) { $this->_expirationDate = $expirationDate; } else { $tz = new DateTimeZone('UTC'); $this->_expirationDate = new DateTime("@$expirationDate", $tz); } return $this; } /** * Sets the id of this sub-key * * @param string $id the id of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setId($id) { $this->_id = strval($id); return $this; } /** * Sets the algorithm used by this sub-key * * @param integer $algorithm the algorithm used by this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setAlgorithm($algorithm) { $this->_algorithm = intval($algorithm); return $this; } /** * Sets the fingerprint of this sub-key * * @param string $fingerprint the fingerprint of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setFingerprint($fingerprint) { $this->_fingerprint = strval($fingerprint); return $this; } /** * Sets the length of this sub-key in bits * * @param integer $length the length of this sub-key in bits. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setLength($length) { $this->_length = intval($length); return $this; } /** * Sets whether or not this sub-key can sign data * * @param boolean $canSign true if this sub-key can sign data and false if * it can not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCanSign($canSign) { if ($canSign) { $this->_usage |= self::USAGE_SIGN; } else { $this->_usage &= ~self::USAGE_SIGN; } return $this; } /** * Sets whether or not this sub-key can encrypt data * * @param boolean $canEncrypt true if this sub-key can encrypt data and * false if it can not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCanEncrypt($canEncrypt) { if ($canEncrypt) { $this->_usage |= self::USAGE_ENCRYPT; } else { $this->_usage &= ~self::USAGE_ENCRYPT; } return $this; } /** * Sets usage flags of the sub-key * * @param integer $usage Usage flags * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setUsage($usage) { $this->_usage = (int) $usage; return $this; } /** * Sets whether of not the private key for this sub-key exists in the * keyring * * @param boolean $hasPrivate true if the private key for this sub-key * exists in the keyring and false if it does * not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setHasPrivate($hasPrivate) { $this->_hasPrivate = ($hasPrivate) ? true : false; return $this; } /** * Sets whether or not this sub-key is revoked * * @param boolean $isRevoked whether or not this sub-key is revoked. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setRevoked($isRevoked) { $this->_isRevoked = ($isRevoked) ? true : false; return $this; } /** * Parses a sub-key object from a sub-key string * * See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for information * on how the sub-key string is parsed. * * @param string $string the string containing the sub-key. * * @return Crypt_GPG_SubKey the sub-key object parsed from the string. */ public static function parse($string) { $tokens = explode(':', $string); $subKey = new Crypt_GPG_SubKey(); $subKey->setId($tokens[4]); $subKey->setLength($tokens[2]); $subKey->setAlgorithm($tokens[3]); $subKey->setCreationDate(self::_parseDate($tokens[5])); $subKey->setExpirationDate(self::_parseDate($tokens[6])); if ($tokens[1] == 'r') { $subKey->setRevoked(true); } $usage = 0; $usage_map = array( 'a' => self::USAGE_AUTHENTICATION, 'c' => self::USAGE_CERTIFY, 'e' => self::USAGE_ENCRYPT, 's' => self::USAGE_SIGN, ); foreach ($usage_map as $key => $flag) { if (strpos($tokens[11], $key) !== false) { $usage |= $flag; } } $subKey->setUsage($usage); return $subKey; } /** * Parses a date string as provided by GPG into a UNIX timestamp * * @param string $string the date string. * * @return DateTime|null the date corresponding to the provided date string. */ private static function _parseDate($string) { if (empty($string)) { return null; } // all times are in UTC according to GPG documentation $timeZone = new DateTimeZone('UTC'); if (strpos($string, 'T') === false) { // interpret as UNIX timestamp $string = '@' . $string; } return new DateTime($string, $timeZone); } }