1
|
|
|
<?php |
2
|
|
|
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionUtil.php"; |
3
|
|
|
//下载 |
4
|
|
|
class AESCBCStreamWriteCallBack{ |
5
|
|
|
private $iv; |
6
|
|
|
private $cek; |
7
|
|
|
private $contentLength; |
8
|
|
|
//数组,分别为上限和下限 |
9
|
|
|
private $expectedRange; |
10
|
|
|
//经过调整后的range |
11
|
|
|
private $adjustedRange; |
12
|
|
|
//当前指针位置 |
13
|
|
|
private $currentIndex; |
14
|
|
|
private $buffer;//上一次调用streaming_write_callback后,未解码的数据 |
15
|
|
|
private $firstWrite = TRUE; |
16
|
|
|
public function __set($property_name, $value){ |
17
|
|
|
$this->$property_name=$value; |
18
|
|
|
} |
19
|
|
|
public function __get($property_name){ |
20
|
|
|
if(isset($this->$property_name)) |
21
|
|
|
{ |
22
|
|
|
return($this->$property_name); |
23
|
|
|
}else |
24
|
|
|
{ |
25
|
|
|
return(NULL); |
26
|
|
|
} |
27
|
|
|
} |
28
|
|
|
//最后的数据大小肯定是blocksize的倍数,所以最后buffer中不会有未解密的内容。否则可以认为该文件是错误的 |
29
|
|
|
public function streaming_write_callback($curl_handle,$data,$write_stream){ |
30
|
|
|
$data = $this->buffer.$data; |
31
|
|
|
|
32
|
|
|
$length = strlen($data); |
33
|
|
|
//不能把上次的没读完的长度算在这次里,应该算在上次 |
34
|
|
|
$written_total = 0-strlen($this->buffer); |
35
|
|
|
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC); |
36
|
|
|
if($length<$blocksize) |
37
|
|
|
$this->buffer = $data; |
38
|
|
|
else{ |
39
|
|
|
//如果期望的范围之后还有数据,则认为数据已经接收完毕。不做任何处理 |
40
|
|
|
if($this->expectedRange["end"] < $this->expectedRange["start"]){ |
41
|
|
|
return $written_total+strlen($data); |
42
|
|
|
} |
43
|
|
|
$this->buffer = substr($data,$length - $length%$blocksize); |
44
|
|
|
$data = substr($data,0,$length - $length%$blocksize); |
45
|
|
|
|
46
|
|
|
$ivoffset = 0; |
47
|
|
|
//range get时,如果不是从刚开始,则应该取加密后数据的前16个字节作为之后解密的iv |
48
|
|
|
if($this->firstWrite){ |
49
|
|
|
$this->firstWrite = FALSE; |
50
|
|
|
if(!$this->isBegin()){ |
51
|
|
|
$this->iv = substr($data,0,$blocksize); |
52
|
|
|
$data = substr($data,$blocksize); |
53
|
|
|
$ivoffset = $blocksize; |
54
|
|
|
} |
55
|
|
|
//初始化当前位置 |
56
|
|
|
if(isset($this->adjustedRange)) |
57
|
|
|
$this->currentIndex = $ivoffset+$this->adjustedRange["start"]; |
58
|
|
|
else |
59
|
|
|
$this->currentIndex = $ivoffset; |
60
|
|
|
} |
61
|
|
|
$written_total+=$ivoffset; |
62
|
|
|
if(strlen($data) == 0){ |
63
|
|
|
$decoded = ""; |
|
|
|
|
64
|
|
|
return $written_total; |
65
|
|
|
}else{ |
66
|
|
|
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); |
67
|
|
|
mcrypt_generic_init($td,$this->cek,$this->iv); |
68
|
|
|
$decoded = mdecrypt_generic($td,$data); |
69
|
|
|
mcrypt_generic_deinit($td); |
70
|
|
|
mcrypt_module_close($td); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
$this->iv = substr($data,strlen($data)-$blocksize); |
74
|
|
|
//判断是否需要删除最后填充的字符,以及获取填充的字符 |
75
|
|
|
$needRemovePad = FALSE; |
76
|
|
|
$pad = NULL; |
77
|
|
|
|
78
|
|
|
if($this->currentIndex+strlen($decoded) >=$this->contentLength){ |
79
|
|
|
$needRemovePad = TRUE; |
80
|
|
|
$pad = ord(substr($decoded,strlen($decoded)-1,1)); |
81
|
|
|
if($pad<=0||$pad>$blocksize) |
82
|
|
|
{ |
83
|
|
|
//invalid pad |
84
|
|
|
$needRemovePad = FALSE; |
85
|
|
|
} |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
//将解密后的数据截取到期望的长度 |
89
|
|
|
$startOffset = 0; |
90
|
|
|
$endOffset = 0; |
91
|
|
|
if(isset($this->expectedRange)){ |
92
|
|
|
$trueEnd = $expectedEnd = $this->expectedRange["end"]; |
93
|
|
|
|
94
|
|
|
if($this->currentIndex+strlen($decoded)>$expectedEnd){ |
95
|
|
|
$preLength = strlen($decoded); |
96
|
|
|
$decoded = substr($decoded, 0,$expectedEnd-$this->currentIndex+1); |
97
|
|
|
$endOffset = $preLength-strlen($decoded); |
98
|
|
|
}else{ |
99
|
|
|
//因为range是开始结束都计算的,range=1-2。currentIndex=1,长度是2,end=currentIndex+2-1 |
100
|
|
|
$trueEnd = $this->currentIndex+strlen($decoded)-1; |
101
|
|
|
} |
102
|
|
|
$expectedStart = $this->expectedRange["start"]; |
103
|
|
|
if($this->currentIndex<$expectedStart){ |
104
|
|
|
$decoded = substr($decoded,$expectedStart - $this->currentIndex); |
105
|
|
|
$startOffset = $expectedStart - $this->currentIndex; |
106
|
|
|
} |
107
|
|
|
//调整下次期望的开始 |
108
|
|
|
$this->expectedRange["start"] = $trueEnd+1; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
$padOffset = 0; |
112
|
|
|
//再次根据截取的长度判断是否需要删除最后填充的字符 |
113
|
|
|
if($needRemovePad&&$endOffset > $pad){ |
114
|
|
|
$needRemovePad = FALSE; |
115
|
|
|
} |
116
|
|
|
$actualWriteCount = 0; |
117
|
|
|
if($needRemovePad){ |
118
|
|
|
$padOffset = $pad-$endOffset; |
119
|
|
|
$actualWriteCount = strlen($decoded)-$padOffset; |
120
|
|
|
if($actualWriteCount <= 0)//负数的情况就是用户期望的range里全是填充的 |
121
|
|
|
$decoded = ""; |
122
|
|
|
else |
123
|
|
|
$decoded = substr($decoded,0,strlen($decoded)-$padOffset); |
124
|
|
|
} |
125
|
|
|
$count = fwrite($write_stream, $decoded); |
126
|
|
|
if($count == 0) |
127
|
|
|
$count = $actualWriteCount; |
128
|
|
|
$count += $padOffset; |
129
|
|
|
$count += $startOffset; |
130
|
|
|
$count += $endOffset; |
131
|
|
|
$this->currentIndex += $count; |
132
|
|
|
$written_total+=$count; |
133
|
|
|
} |
134
|
|
|
//否则curl框架会报错 |
135
|
|
|
$written_total+=strlen($this->buffer); |
136
|
|
|
return $written_total; |
137
|
|
|
} |
138
|
|
|
//是的话则使用初始化IV |
139
|
|
|
private function isBegin(){ |
140
|
|
|
$beginIndex = 0; |
141
|
|
|
if(isset($this->adjustedRange["start"])) |
142
|
|
|
$beginIndex = $this->adjustedRange["start"]; |
143
|
|
|
if($beginIndex == 0) |
144
|
|
|
return TRUE; |
145
|
|
|
else |
146
|
|
|
return FALSE; |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
//上传 |
150
|
|
|
class AESCBCStreamReadCallBack{ |
151
|
|
|
private $iv; |
152
|
|
|
private $cek; |
153
|
|
|
private $contentLength; |
154
|
|
|
private $buffer; |
155
|
|
|
private $hasread = 0; |
156
|
|
|
private $mutipartUpload =FALSE; |
157
|
|
|
private $isLastPart = FALSE; |
158
|
|
|
public function __set($property_name, $value){ |
159
|
|
|
$this->$property_name=$value; |
160
|
|
|
} |
161
|
|
|
public function __get($property_name){ |
162
|
|
|
if(isset($this->$property_name)) |
163
|
|
|
{ |
164
|
|
|
return($this->$property_name); |
165
|
|
|
}else |
166
|
|
|
{ |
167
|
|
|
return(NULL); |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
public function streaming_read_callback($curl_handle,$file_handle,$length,$read_stream,$seek_position){ |
171
|
|
|
// Once we've sent as much as we're supposed to send... |
172
|
|
|
if ($this->hasread >= $this->contentLength) |
173
|
|
|
{ |
174
|
|
|
// Send EOF |
175
|
|
|
return ''; |
176
|
|
|
} |
177
|
|
|
// If we're at the beginning of an upload and need to seek... |
178
|
|
|
if ($this->hasread == 0 && $seek_position>0 && $seek_position !== ftell($read_stream)) |
179
|
|
|
{ |
180
|
|
|
if (fseek($read_stream, $seek_position) !== 0) |
181
|
|
|
{ |
182
|
|
|
throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
|
187
|
|
|
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_ECB); |
188
|
|
|
$needRead = min($this->contentLength - $this->hasread,$length); |
189
|
|
|
$read = fread($read_stream,$needRead); |
190
|
|
|
$this->hasread += strlen($read); |
191
|
|
|
$isLast = FALSE; |
192
|
|
|
if($this->hasread >= $this->contentLength){ |
193
|
|
|
$isLast = TRUE; |
194
|
|
|
} |
195
|
|
|
$data = $this->buffer.$read; |
196
|
|
|
|
197
|
|
|
$dataLength = strlen($data); |
198
|
|
|
|
199
|
|
|
if(!$isLast){ |
200
|
|
|
$this->buffer = substr($data,$dataLength-$dataLength%$blocksize); |
201
|
|
|
$data = substr($data, 0,$dataLength-$dataLength%$blocksize); |
202
|
|
|
}else{ |
203
|
|
|
//分块上传除最后一块外肯定是blocksize大小的倍数,所以不需要填充。 |
204
|
|
|
if($this->mutipartUpload){ |
205
|
|
|
if($this->isLastPart){ |
206
|
|
|
$this->buffer = NULL; |
207
|
|
|
$data = EncryptionUtil::PKCS5Padding($data,$blocksize); |
208
|
|
|
}else{ |
209
|
|
|
//donothing |
210
|
|
|
} |
211
|
|
|
}else{ |
212
|
|
|
$this->buffer = NULL; |
213
|
|
|
$data = EncryptionUtil::PKCS5Padding($data,$blocksize); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); |
217
|
|
|
mcrypt_generic_init($td,$this->cek,$this->iv); |
218
|
|
|
$encrypted = mcrypt_generic($td,$data); |
219
|
|
|
mcrypt_generic_deinit($td); |
220
|
|
|
//去除自动填充的16个字节//php的当恰好为16的倍数时竟然不填充? |
221
|
|
|
//$encrypted = substr($encrypted,0,strlen($encrypted)-$blocksize); |
222
|
|
|
//取最后一个block作为下一次的iv |
223
|
|
|
$this->iv = substr($encrypted, strlen($encrypted)-$blocksize); |
224
|
|
|
return $encrypted; |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
?> |
|
|
|
|