static function unpack_octets($packed) { $j = 0; $i = 0; $l = count($packed); $r = array_fill(0, $l * 4, 0); for ($j = 0; $j < $l; $j++) { $r[$i++] = GPG_Utility::B0($packed[$j]); $r[$i++] = GPG_Utility::B1($packed[$j]); $r[$i++] = GPG_Utility::B2($packed[$j]); $r[$i++] = GPG_Utility::B3($packed[$j]); } return $r; }
static function encrypt($block, $ctx) { $RCON = GPG_Cipher::$RCON; $S = GPG_Cipher::$S; $T1 = GPG_Cipher::$T1; $T2 = GPG_Cipher::$T2; $T3 = GPG_Cipher::$T3; $T4 = GPG_Cipher::$T4; $r = 0; $t0 = 0; $t1 = 0; $t2 = 0; $t3 = 0; $b = GPG_Utility::pack_octets($block); $rounds = $ctx->rounds; $b0 = $b[0]; $b1 = $b[1]; $b2 = $b[2]; $b3 = $b[3]; for ($r = 0; $r < $rounds - 1; $r++) { $t0 = $b0 ^ $ctx->rk[$r][0]; $t1 = $b1 ^ $ctx->rk[$r][1]; $t2 = $b2 ^ $ctx->rk[$r][2]; $t3 = $b3 ^ $ctx->rk[$r][3]; $b0 = $T1[$t0 & 255] ^ $T2[$t1 >> 8 & 255] ^ $T3[$t2 >> 16 & 255] ^ $T4[GPG_Utility::zshift($t3, 24)]; $b1 = $T1[$t1 & 255] ^ $T2[$t2 >> 8 & 255] ^ $T3[$t3 >> 16 & 255] ^ $T4[GPG_Utility::zshift($t0, 24)]; $b2 = $T1[$t2 & 255] ^ $T2[$t3 >> 8 & 255] ^ $T3[$t0 >> 16 & 255] ^ $T4[GPG_Utility::zshift($t1, 24)]; $b3 = $T1[$t3 & 255] ^ $T2[$t0 >> 8 & 255] ^ $T3[$t1 >> 16 & 255] ^ $T4[GPG_Utility::zshift($t2, 24)]; } $r = $rounds - 1; $t0 = $b0 ^ $ctx->rk[$r][0]; $t1 = $b1 ^ $ctx->rk[$r][1]; $t2 = $b2 ^ $ctx->rk[$r][2]; $t3 = $b3 ^ $ctx->rk[$r][3]; $b[0] = GPG_Cipher::F1($t0, $t1, $t2, $t3) ^ $ctx->rk[$rounds][0]; $b[1] = GPG_Cipher::F1($t1, $t2, $t3, $t0) ^ $ctx->rk[$rounds][1]; $b[2] = GPG_Cipher::F1($t2, $t3, $t0, $t1) ^ $ctx->rk[$rounds][2]; $b[3] = GPG_Cipher::F1($t3, $t0, $t1, $t2) ^ $ctx->rk[$rounds][3]; return GPG_Utility::unpack_octets($b); }
/** * GPG Encypts a message to the provided public key * * @param GPG_Public_Key $pk * @param string $plaintext * @return string encrypted text */ function encrypt($pk, $plaintext) { // normalize the public key $key_id = $pk->GetKeyId(); $key_type = $pk->GetKeyType(); $public_key = $pk->GetPublicKey(); $session_key = GPG_Utility::s_random($this->width, 0); $key_id = GPG_Utility::hex2bin($key_id); $cp = $this->gpg_session($key_id, $key_type, $session_key, $public_key) . $this->gpg_data($session_key, $plaintext); $code = base64_encode($cp); $code = wordwrap($code, 60, "\n", 1); return "-----BEGIN PGP MESSAGE-----\nVersion: VerySimple PHP-GPG v" . $this->version . "\n\n" . $code . "\n=" . base64_encode(GPG_Utility::crc24($cp)) . "\n-----END PGP MESSAGE-----\n"; }
function Expanded_Key($key) { $RCON = GPG_Cipher::$RCON; $S = GPG_Cipher::$S; $maxkc = GPG_Cipher::$maxkc; $maxrk = GPG_Cipher::$maxrk; $kc = 0; $i = 0; $j = 0; $r = 0; $t = 0; $rounds = 0; $keySched = array_fill(0, $maxrk + 1, 0); $keylen = strlen($key); $k = array_fill(0, $maxkc, 0); $tk = array_fill(0, $maxkc, 0); $rconpointer = 0; if ($keylen == 16) { $rounds = 10; $kc = 4; } else { if ($keylen == 24) { $rounds = 12; $kc = 6; } else { if ($keylen == 32) { $rounds = 14; $kc = 8; } else { return; } } } for ($i = 0; $i < $maxrk + 1; $i++) { $keySched[$i] = array_fill(0, 4, 0); } for ($i = 0, $j = 0; $j < $keylen; $j++, $i += 4) { if ($i < $keylen) { $k[$j] = ord($key[$i]) | ord($key[$i + 1]) << 0x8 | ord($key[$i + 2]) << 0x10 | ord($key[$i + 3]) << 0x18; } else { $k[$j] = 0; } } for ($j = $kc - 1; $j >= 0; $j--) { $tk[$j] = $k[$j]; } $r = 0; $t = 0; for ($j = 0; $j < $kc && $r < $rounds + 1;) { for (; $j < $kc && $t < 4; $j++, $t++) { $keySched[$r][$t] = $tk[$j]; } if ($t == 4) { $r++; $t = 0; } } while ($r < $rounds + 1) { $temp = $tk[$kc - 1]; $tk[0] ^= $S[GPG_Utility::B1($temp)] | $S[GPG_Utility::B2($temp)] << 0x8 | $S[GPG_Utility::B3($temp)] << 0x10 | $S[GPG_Utility::B0($temp)] << 0x18; $tk[0] ^= $RCON[$rconpointer++]; if ($kc != 8) { for ($j = 1; $j < $kc; $j++) { $tk[$j] ^= $tk[$j - 1]; } } else { for ($j = 1; $j < $kc / 2; $j++) { $tk[$j] ^= $tk[$j - 1]; } $temp = $tk[$kc / 2 - 1]; $tk[$kc / 2] ^= $S[GPG_Utility::B0($temp)] | $S[GPG_Utility::B1($temp)] << 0x8 | $S[GPG_Utility::B2($temp)] << 0x10 | $S[GPG_Utility::B3($temp)] << 0x18; for ($j = $kc / 2 + 1; $j < $kc; $j++) { $tk[$j] ^= $tk[$j - 1]; } } for ($j = 0; $j < $kc && $r < $rounds + 1;) { for (; $j < $kc && $t < 4; $j++, $t++) { $keySched[$r][$t] = $tk[$j]; } if ($t == 4) { $r++; $t = 0; } } } $this->rounds = $rounds; $this->rk = $keySched; return $this; }
static function F1($x0, $x1, $x2, $x3) { $T1 = GPG_Cipher::$T1; return GPG_Utility::B1($T1[$x0 & 0xff]) | GPG_Utility::B1($T1[$x1 >> 0x8 & 0xff]) << 0x8 | GPG_Utility::B1($T1[$x2 >> 0x10 & 0xff]) << 0x10 | GPG_Utility::B1($T1[GPG_Utility::zshift($x3, 0x18)]) << 0x18; }
function GPG_Public_Key($asc) { $found = 0; $i = strpos($asc, "-----BEGIN PGP PUBLIC KEY BLOCK-----"); if ($i === false) { throw new Exception("Missing block header in Public Key"); } // normalize line breaks $asc = str_replace("\r\n", "\n", $asc); // remove all "comment" lines which we should ignore $lines = explode("\n", $asc); for ($ln = 0; $ln < count($lines); $ln++) { $line = $lines[$ln]; if (GPG_Utility::starts_with(strtolower(trim($line)), "comment:")) { echo "REMOVING LINE\n"; unset($lines[$ln]); } } $asc = implode("\n", $lines); $a = strpos($asc, "\n", $i); if ($a > 0) { $a = strpos($asc, "\n", $a + 1); } $e = strpos($asc, "\n=", $i); if ($a > 0 && $e > 0) { $asc = substr($asc, $a + 2, $e - $a - 2); } else { throw new Exception("Unsupported Public Key format"); } $len = 0; $s = base64_decode($asc); $sa = str_split($s); for ($i = 0; $i < strlen($s);) { $tag = ord($sa[$i++]); if (($tag & 128) == 0) { break; } if ($tag & 64) { $tag &= 63; $len = ord($sa[$i++]); if ($len > 191 && $len < 224) { $len = ($len - 192 << 8) + ord($sa[$i++]); } else { if ($len == 255) { $len = (ord($sa[$i++]) << 24) + (ord($sa[$i++]) << 16) + (ord($sa[$i++]) << 8) + ord($sa[$i++]); } else { if ($len > 223 && len < 255) { $len = 1 << ($len & 0x1f); } } } } else { $len = $tag & 3; $tag = $tag >> 2 & 15; if ($len == 0) { $len = ord($sa[$i++]); } else { if ($len == 1) { $len = (ord($sa[$i++]) << 8) + ord($sa[$i++]); } else { if ($len == 2) { $len = (ord($sa[$i++]) << 24) + (ord($sa[$i++]) << 16) + (ord($sa[$i++]) << 8) + ord($sa[$i++]); } else { $len = strlen($s) - 1; } } } } if ($tag == 6 || $tag == 14) { $k = $i; $version = ord($sa[$i++]); $found = 1; $this->version = $version; $time = (ord($sa[$i++]) << 24) + (ord($sa[$i++]) << 16) + (ord($sa[$i++]) << 8) + ord($sa[$i++]); if ($version == 2 || $version == 3) { $valid = ord($sa[$i++]) << 8 + ord($sa[$i++]); } $algo = ord($sa[$i++]); if ($algo == 1 || $algo == 2) { $m = $i; $lm = floor((ord($sa[$i]) * 256 + ord($sa[$i + 1]) + 7) / 8); $i += $lm + 2; $mod = substr($s, $m, $lm + 2); $le = floor((ord($sa[$i]) * 256 + ord($sa[$i + 1]) + 7) / 8); $i += $le + 2; $this->public_key = base64_encode(substr($s, $m, $lm + $le + 4)); $this->type = "RSA"; if ($version == 3) { $this->fp = ''; $this->key_id = bin2hex(substr($mod, strlen($mod) - 8, 8)); } else { if ($version == 4) { $pkt = chr(0x99) . chr($len >> 8) . chr($len & 255) . substr($s, $k, $len); $fp = sha1($pkt); $this->fp = $fp; $this->key_id = substr($fp, strlen($fp) - 16, 16); } else { $this->fp = ""; $this->key_id = ""; } } $found = 2; } else { if (($algo == 16 || $algo == 20) && $version == 4) { $m = $i; $lp = floor((ord($sa[$i]) * 256 + ord($sa[$i + 1]) + 7) / 8); $i += $lp + 2; $lg = floor((ord($sa[$i]) * 256 + ord($sa[$i + 1]) + 7) / 8); $i += $lg + 2; $ly = floor((ord($sa[$i]) * 256 + ord($sa[$i + 1]) + 7) / 8); $i += $ly + 2; $this->public_key = base64_encode(substr($s, $m, $lp + $lg + $ly + 6)); $pkt = chr(0x99) . chr($len >> 8) . chr($len & 255) . substr($s, $k, $len); $fp = sha1($pkt); $this->fp = $fp; $this->key_id = substr($fp, strlen($fp) - 16, 16); $this->type = "ELGAMAL"; $found = 3; } else { $i = $k + $len; } } } else { if ($tag == 13) { $this->user = substr($s, $i, $len); $i += $len; } else { $i += $len; } } } if ($found < 2) { throw new Exception("Unable to parse Public Key"); // $this->version = ""; // $this->fp = ""; // $this->key_id = ""; // $this->user = ""; // $this->public_key = ""; } }