|
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
|
|
|
?> |
|
|
|
|
|