| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- <?php
- namespace ACES\Common;
- use ACES\Common\Exception as Ex;
- use ACES\Common\Exception\MalformedException;
- use Common\Exception\SignException;
- class MKey
- {
- const IV_SIZE = 16;
- const RANDOM_SIZE = 4;
- const KEY_ID_LEN = 16;
- //1024 * 1024
- const MEGABYTE = 1048576;
-
- private $id;
- private $key;
- private $ver;
- private $service;
- private $keyUsage;
- private $keyType;
- private $skey;
-
- private $svkey; // for sign & verify
-
- private $isValid;
- private $effective;
- private $expired;
- private $key_digest;
- private $keyStatus;
-
- public function __construct(
- $service,
- $kid,
- $key,
- $kdigest,
- $kver,
- $effectiveTs,
- $expTs,
- $ktype,
- $kusage,
- $kstatus)
- {
- if(empty($kid) || empty($service))
- throw new MalformedException("ID and App fields cannot be null.");
-
- $this->service = $service;
- $this->id = $kid;
- $this->key = $key;
-
- if($kver < -1){
- throw new MalformedException("Invalid key version.");
- }
- $this->ver = $kver;
-
- $this->keyUsage = KEY_USAGE::fromValue($kusage);
- $this->keyStatus = KEY_STATUS::fromValue($kstatus);
- $this->keyType = KEY_TYPE::fromValue($ktype);
-
- $this->isValid = false;
- if(!empty($key)){
- $this->key = $key;
- $this->expired = $expTs;
- $this->effective = $effectiveTs;
- // TODO: due to cryptographic policy control, JDK only allow AES 128 bit
- $this->skey = substr($this->key, 0, 16);
- $this->svkey = $this->key;
- }
-
- $this->key_digest = $kdigest;
- $digest = base64_encode(hash(Constants::DEFAULT_CERTDIGEST_ALGO, $this->key, TRUE));
-
- if(strcmp($this->key_digest, $digest)==0){
- $this->isValid = TRUE;
- }
- }
- function __destruct()
- {
- // TODO - Insert your code here
- }
-
- public function encrypt($pt)
- {
- $ct = KeyEncryption::encrypt($this, $pt);
-
- $ct = pack("C",Constants::CIPHER_TYPE_WEAK) .pack("C",Constants::ALGO_TYPE_AES_CBC_128) . $this->id . $ct;
-
- return $ct;
- }
-
- public function strong_encrypt($pt){
- $de = new DataEncryption();
-
- $data_cipher = $de->encrypt($pt);
- $key_cipher = KeyEncryption::wrap($this, $de->exportKey());
-
- $ct = pack("C", Constants::CIPHER_TYPE_REGULAR) . pack("n", strlen($this->id)) .
- $this->id . pack("C", Constants::ALGO_TYPE_AES_CBC_128) . pack("n", strlen($key_cipher)) .
- $key_cipher . pack("C", Constants::ALGO_TYPE_AES_CBC_128) . pack("N", strlen($data_cipher)) . $data_cipher;
-
- return $ct;
- }
-
- public function strong_decrypt($ct){
- $offset = 0;
- $ctype_ = unpack("C", $ct[$offset]);
- $ctype = $ctype_[1];
- $offset += 1;
- if($ctype != Constants::CIPHER_TYPE_REGULAR){
- throw new MalformedException("Unmatched CipherText Type.");
- }
- $eidLen_ = unpack("n", substr($ct, $offset, 2));
- $eidLen = $eidLen_[1];
- $offset += 2;
- if($eidLen !== Constants::DEFAULT_KEYID_LEN){
- throw new MalformedException("Corrupted ciphertext header with illegal key id length.");
- }
-
- $eid = substr($ct, $offset, $eidLen);
- $offset += $eidLen;
- if ($this->id != $eid){
- throw new MalformedException("Unmatched MKey ID.");
- }
- $atype_ = unpack("C", substr($ct, $offset, 1));
- $atype = $atype_[1];
- $offset += 1;
- if($atype != Constants::ALGO_TYPE_AES_CBC_128){
- throw new MalformedException("Unmatched Key Encryption Algorithm Type:$atype");
- }
- $kcipherLen_ = unpack("n", substr($ct, $offset, 2));
- $kcipherLen = $kcipherLen_[1];
- $offset += 2;
- if($kcipherLen < Constants::DEFAULT_CIPHERBLK_LEN || $kcipherLen > strlen(substr($ct, $offset))){
- throw new MalformedException("Corrupted ciphertext header with illegal key cipher length.");
- }
- $kcipher = substr($ct, $offset, $kcipherLen);
- $offset += $kcipherLen;
- $dkey = KeyEncryption::unwrap($this, $kcipher);
- $dtype_ = unpack("C", substr($ct, $offset, 1));
- $dtype = $dtype_[1];
- $offset += 1;
- if($dtype != Constants::ALGO_TYPE_AES_CBC_128){
- throw new MalformedException("Unmatched Data Encryption Algorithm Type:$dtype");
- }
- $dcipherLen_ = unpack("N", substr($ct, $offset, 4));
- $dcipherLen = $dcipherLen_[1];
- $offset += 4;
- if($dcipherLen != strlen(substr($ct, $offset))){
- throw new MalformedException("Corrupted ciphertext header with illegal data cipher length.");
- }
-
- $dcipher = substr($ct, $offset);
-
- $de = new DataEncryption($dkey);
- $pt = $de->decrypt($dcipher);
-
- return $pt;
-
- }
-
- public function decrypt($ct)
- {
- $offset = 0;
-
- // Get and validate cipher type
- $ctype_ = unpack("C", substr($ct, $offset, Constants::CIPHER_TYPE_LEN));
- $ctype = $ctype_[1];
- $offset += Constants::CIPHER_TYPE_LEN;
- if($ctype != Constants::CIPHER_TYPE_WEAK)
- throw new Ex\MalformedException("Unmatch Encryption Algorithm Type: $ctype");
-
- // Get and validate algo type
- $atype_ = unpack("C", substr($ct, $offset, Constants::ALGO_TYPE_LEN));
- $atype = $atype_[1];
- $offset += Constants::ALGO_TYPE_LEN;
- if($atype != Constants::ALGO_TYPE_AES_CBC_128)
- throw new Ex\MalformedException("Unmatch Encryption Algorithm Type: $atype");
-
- $eid = substr($ct, $offset, Constants::DEFAULT_KEYID_LEN);
- $offset += Constants::DEFAULT_KEYID_LEN;
- if($eid != $this->id)
- throw new MalformedException("Unmatch MKey ID.");
-
- $ct_data = substr($ct, $offset);
-
- $pt = KeyEncryption::decrypt($this, $ct_data);
-
- return $pt;
- }
-
- public function sign($input){
- if($input === NULL){
- throw new MalformedException("Illegal input.");
- }
-
- if ($this->id == NULL || strlen($this->id) != Constants::DEFAULT_KEYID_LEN) {
- throw new MalformedException("Illegal Signing Key.");
- }
-
- $rsec = Crypto::secureRandom(Constants::DEFAULT_SEED_LEN);
- $data = $input.$rsec;
- $signedData = hash_hmac(Constants::DEFAULT_TOKEN_SIGN_ALGO, $data, $this->svkey, TRUE);
-
- if($signedData === FALSE)
- throw new SignException("Sign fail, algo:".Constants::DEFAULT_TOKEN_SIGN_ALGO);
-
- $ret = $this->id.$rsec.$signedData;
-
- return base64_encode($ret);
- }
-
- public function verify($input, $sig){
- if($input === NULL){
- throw new MalformedException("Illegal input.");
- }
-
- if($sig === NULL || strlen($sig) < Constants::DEFAULT_KEYID_LEN + Constants::DEFAULT_SEED_LEN){
- throw new MalformedException("Illegal Signature.");
- }
- // skip key id
- $offset = Constants::DEFAULT_KEYID_LEN;
-
- $sig = base64_decode($sig);
-
- $rsec = substr($sig, $offset, Constants::DEFAULT_SEED_LEN);
- $offset += Constants::DEFAULT_SEED_LEN;
-
- $carriedSig = substr($sig, $offset);
-
- $data = $input.$rsec;
-
- $signedData = hash_hmac(Constants::DEFAULT_TOKEN_SIGN_ALGO, $data, $this->svkey, TRUE);
-
- return $carriedSig == $signedData;
- }
-
- public function getKey() { return $this->skey; }
-
- public function getRawKey(){
- return $this->key;
- }
-
- public function isValid() {
- return $this->isValid;
- }
-
- public function getID() {
- return $this->id;
- }
-
- public function getEffectiveTime(){
- return $this->effective;
- }
-
- public function getKeyStatus(){
- return $this->keyStatus;
- }
-
- public function getVersion(){
- return $this->ver;
- }
-
- public function getKeyUsage(){
- return $this->keyUsage;
- }
-
- public function getExpiredTime(){
- return $this->expired;
- }
- }
|