3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 class BlobExpiredException extends Exception {
25 * This class provides basic binary blob encryption and decryption, for use with the security token
28 class BasicBlobCrypter extends BlobCrypter {
29 //FIXME make this compatible with the java's blobcrypter
32 // Labels for key derivation
33 private $CIPHER_KEY_LABEL = 0;
34 private $HMAC_KEY_LABEL = 1;
36 /** Key used for time stamp (in seconds) of data */
37 public $TIMESTAMP_KEY = "t";
39 /** minimum length of master key */
40 public $MASTER_KEY_MIN_LEN = 16;
42 /** allow three minutes for clock skew */
43 private $CLOCK_SKEW_ALLOWANCE = 180;
45 private $UTF8 = "UTF-8";
49 protected $allowPlaintextToken;
51 public function __construct() {
52 $this->cipherKey = 'INSECURE_DEFAULT_KEY';
53 $this->hmacKey = 'INSECURE_DEFAULT_KEY';
54 $this->allowPlaintextToken = true;
60 public function wrap(Array $in) {
61 $encoded = $this->serializeAndTimestamp($in);
62 if (! function_exists('mcrypt_module_open') && $this->allowPlaintextToken) {
63 $cipherText = base64_encode($encoded);
65 $cipherText = Crypto::aes128cbcEncrypt($this->cipherKey, $encoded);
67 $hmac = Crypto::hmacSha1($this->hmacKey, $cipherText);
68 $b64 = base64_encode($cipherText . $hmac);
72 private function serializeAndTimestamp(Array $in) {
74 foreach ($in as $key => $val) {
75 $encoded .= urlencode($key) . "=" . urlencode($val) . "&";
77 $encoded .= $this->TIMESTAMP_KEY . "=" . time();
84 public function unwrap($in, $maxAgeSec) {
85 //TODO remove this once we have a better way to generate a fake token in the example files
86 if ($this->allowPlaintextToken && count(explode(':', $in)) == 6) {
87 $data = explode(":", $in);
96 $bin = base64_decode($in);
97 $cipherText = substr($bin, 0, strlen($bin) - Crypto::$HMAC_SHA1_LEN);
98 $hmac = substr($bin, strlen($cipherText));
99 Crypto::hmacSha1Verify($this->hmacKey, $cipherText, $hmac);
100 if (! function_exists('mcrypt_module_open') && $this->allowPlaintextToken) {
101 $plain = base64_decode($cipherText);
103 $plain = Crypto::aes128cbcDecrypt($this->cipherKey, $cipherText);
105 $out = $this->deserialize($plain);
106 $this->checkTimestamp($out, $maxAgeSec);
111 private function deserialize($plain) {
113 $items = preg_split("/&|=/", $plain);
114 for ($i = 0; $i < count($items);) {
115 $key = urldecode($items[$i ++]);
116 $value = urldecode($items[$i ++]);
122 private function checkTimestamp(Array $out, $maxAge) {
123 $minTime = (int)$out[$this->TIMESTAMP_KEY] - $this->CLOCK_SKEW_ALLOWANCE;
124 $maxTime = (int)$out[$this->TIMESTAMP_KEY] + $maxAge + $this->CLOCK_SKEW_ALLOWANCE;
126 if (! ($minTime < $now && $now < $maxTime)) {
127 throw new BlobExpiredException("Security token expired");