584417de5b2fa50a30e33d11e1cc6ed9627374e4
[atutor.git] / docs / mods / _standard / social / lib / BasicBlobCrypter.php
1 <?php
2 /**
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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
18  * under the License.
19  */
20
21 class BlobExpiredException extends Exception {
22 }
23
24 /**
25  * This class provides basic binary blob encryption and decryption, for use with the security token
26  * 
27  */
28 class BasicBlobCrypter extends BlobCrypter {
29   //FIXME make this compatible with the java's blobcrypter
30   
31
32   // Labels for key derivation
33   private $CIPHER_KEY_LABEL = 0;
34   private $HMAC_KEY_LABEL = 1;
35   
36   /** Key used for time stamp (in seconds) of data */
37   public $TIMESTAMP_KEY = "t";
38   
39   /** minimum length of master key */
40   public $MASTER_KEY_MIN_LEN = 16;
41   
42   /** allow three minutes for clock skew */
43   private $CLOCK_SKEW_ALLOWANCE = 180;
44   
45   private $UTF8 = "UTF-8";
46   
47   private $cipherKey;
48   private $hmacKey;
49   protected $allowPlaintextToken;
50
51   public function __construct() {
52     $this->cipherKey = 'INSECURE_DEFAULT_KEY';
53     $this->hmacKey = 'INSECURE_DEFAULT_KEY';
54     $this->allowPlaintextToken = true;
55   }
56
57   /**
58    * {@inheritDoc}
59    */
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);
64     } else {
65       $cipherText = Crypto::aes128cbcEncrypt($this->cipherKey, $encoded);
66     }
67     $hmac = Crypto::hmacSha1($this->hmacKey, $cipherText);
68     $b64 = base64_encode($cipherText . $hmac);
69     return $b64;
70   }
71
72   private function serializeAndTimestamp(Array $in) {
73     $encoded = "";
74     foreach ($in as $key => $val) {
75       $encoded .= urlencode($key) . "=" . urlencode($val) . "&";
76     }
77     $encoded .= $this->TIMESTAMP_KEY . "=" . time();
78     return $encoded;
79   }
80
81   /**
82    * {@inheritDoc}
83    */
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);
88       $out = array();
89       $out['o'] = $data[0];
90       $out['v'] = $data[1];
91       $out['a'] = $data[2];
92       $out['d'] = $data[3];
93       $out['u'] = $data[4];
94       $out['m'] = $data[5];
95     } else {
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);
102       } else {
103         $plain = Crypto::aes128cbcDecrypt($this->cipherKey, $cipherText);
104       }
105       $out = $this->deserialize($plain);
106       $this->checkTimestamp($out, $maxAgeSec);
107     }
108     return $out;
109   }
110
111   private function deserialize($plain) {
112     $map = array();
113     $items = preg_split("/&|=/", $plain);
114     for ($i = 0; $i < count($items);) {
115       $key = urldecode($items[$i ++]);
116       $value = urldecode($items[$i ++]);
117       $map[$key] = $value;
118     }
119     return $map;
120   }
121
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;
125     $now = time();
126     if (! ($minTime < $now && $now < $maxTime)) {
127       throw new BlobExpiredException("Security token expired");
128     }
129   }
130 }