Neo中hash算法,加密算法使用介绍
深圳林妙可
发表于 2023-1-5 00:08:26
200
0
0
) T9 o. M2 t8 o& `
关于区块链中密码学的介绍,yeasy大牛的文章已经介绍的非常好,下文主要通过和Neo结合,加上一些自己的理解,去讲述一下加密算法的使用方法。" G5 W2 m3 B* I# H1 K
Hash 算法+ M1 S. {, I0 @9 p' G
' l& n8 y: j& t. d- g& F1 q- R
Hash (哈希或散列)算法是信息技术领域非常基础也非常重要的技术。它能任意长度的二进制值(明文)映射为较短的固定长度的二进制值(Hash 值),并且不同的明文很难映射为相同的 Hash 值。/ h3 s5 k3 I/ Q$ z5 {( s
hash函数的作用2 o8 F& g$ i g4 e+ K" h; S8 X
注意上一篇文章说明了如何将hash后的字符串保存到Neo的UInt256类型,其中一个前提就是结果集合在[0-15]之间。
哈希完全不等于加密,很多时候开发人员都对用户表中的密码进行哈希后保存,实际上不叫做加密,只是相当于把密码的“特征指纹”保存下来,而对非法攻击者来说,在不知道真实的“密码”的情况下,得到有相同指纹的密码是极为困难的。
# S7 ^7 L( k4 c; L1 f
一个优秀的 hash 算法,将能实现:
正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。% N& D( Y( N; h# n+ e: t- t- S% ?7 d
4 |, _9 K% \% `+ Z c2 Q
逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出明文。) i6 m+ H4 b: Q1 E
输入敏感:原始输入信息修改一点信息,产生的 hash 值看起来应该都有很大不同。
& S3 S( v- R' d L" a
冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值一致(发生冲突)。1 P0 p! V+ S& w5 Q# r
目前,一般认为 MD5 和 SHA1 已经不够安全,推荐至少使用 SHA2-256 算法。
一般的,Hash 算法都是算力敏感型,意味着计算资源是瓶颈,主频越高的 CPU 进行 Hash 的速度也越快。9 J/ l. j& [6 d& k: c' [
也有一些 Hash 算法不是算力敏感的,例如 scrypt,需要大量的内存资源,节点不能通过简单的增加更多 CPU 来获得 hash 性能的提升。
Neo中的hash算法0 R5 i# Z7 u/ n0 v0 z* Q4 e+ o& U
scrypt5 u" Q. H1 v, S
scrpyt算法是由著名的FreeBSD黑客 Colin Percival为他的备份服务 Tarsnap开发的,当初的设计是为了降低CPU负荷,尽量少的依赖cpu计算,利用CPU闲置时间进行计算,因此scrypt不仅计算所需时间长,而且占用的内存也多,使得并行计算多个摘要异常困难,因此利用rainbow table进行暴力攻击更加困难。scrypt没有在生产环境中大规模应用,并且缺乏仔细的审察和广泛的函数库支持。所以scrpyt一直没有推广开,但是由于其内存依赖的设计特别符合当时对抗专业矿机的设计,成为数字货币算法发展的一个主要应用方向。
$ D2 H1 p# A, B6 f& q) A) ~
scrypt的参数9 X/ ?2 \4 [# P
% F8 R& ?0 Q# z& P
https://stackoverflow.com/questi ... scrypt-work-factors
Cpercival mentioned in his slides from 2009 something around- A9 i! M- b/ K. O( e2 ~
7 M* t/ }7 `% l4 M, ^: a4 V
(N = 2^14, r = 8, p = 1) for M) r# t% v9 h0 o# \- {3 r8 i: b
scrypt特点
scrpyt的出名主要是因为莱特币为了抵抗比特币矿机采用的一个算法,可以指定内存和cpu的使用量,可以用参数确定hash的时间。
Neo中如何使用scrypt7 }* @7 o) V2 W# b5 o+ x
& e( p5 A. X& v- \* \9 t' v
// in NEP6Account4 v' w( C& g% Z' P7 D
public NEP6Account(NEP6Wallet wallet,
UInt160 scriptHash, KeyPair key, string password) \- y9 b7 t5 o, G
( \5 v+ ^: H0 ]0 J1 B& M
: this(wallet,
! w2 p1 I( x5 z9 y2 p0 o1 k
scriptHash,
. B2 S1 g0 C6 Z; k% @
key.Export(password, wallet.Scrypt.N, wallet.Scrypt.R, wallet.Scrypt.P))
+ p$ _) j: _4 c$ f! L) [
{
3 G5 _9 P5 ]) v; W, W# D' k
this.key = key;
% f% h/ f4 L- R& w8 P+ i
}
2 }2 `- w, P6 i, z; f5 D v; c
// in class KeyPair
: \, M4 u+ A( X: g) e* @) K/ M7 o
public string Export(string passphrase, int N = 16384, int r = 8, int p = 8)
{' J/ w6 B O0 Z
using (Decrypt())4 z( {; X& s- {0 X5 {& U J$ y' ]
{1 R" Y& \" d& W/ Q% s
5 d, ]) j, R' X
UInt160 script_hash = Contract.7 M6 ~4 c+ B. {+ H
CreateSignatureRedeemScript(PublicKey).ToScriptHash();
3 E3 B3 }0 o3 q4 Y+ E! @. c. G
# `& x4 ]8 m6 L5 N6 y( M0 I
string address = Wallet.ToAddress(script_hash);8 N8 m2 b8 S- u9 o b6 U% v
8 n% C! t% J: a( z. t; N2 p
byte[] addresshash = Encoding.ASCII.GetBytes(address)5 y9 l) B$ p N4 [, U
.Sha256().Sha256().Take(4).ToArray();
$ n$ |0 B( }9 a! l) u! g
byte[] derivedkey = SCrypt.DeriveKey(
Encoding.UTF8.GetBytes(passphrase), addresshash, N, r, p, 64);
. j) v% O ~5 \% f. x! A
$ r. L+ u7 N* a
% q- X* l! T; r6 z/ y2 E
byte[] derivedhalf1 = derivedkey.Take(32).ToArray();
) `9 D: K/ A* y. k. V/ m m
byte[] derivedhalf2 = derivedkey.Skip(32).ToArray();
* s4 a, d% T/ p" p( _, I
byte[] encryptedkey = XOR(PrivateKey, derivedhalf1)0 ?" \4 z/ h8 V9 I; @; X
' Q( w! i6 Q7 [, c
.AES256Encrypt(derivedhalf2);0 _4 n+ _/ e W J7 i2 l
1 s+ S) X0 z# E" {. Y4 u1 _ V& n9 d& g
byte[] buffer = new byte[39];, d/ v5 v+ k. f. H+ s
: H* c. q* f/ E. z+ T$ ]7 E( d/ W
buffer[0] = 0x01;$ C4 Q7 w$ T, h6 c: Z2 A# E
buffer[1] = 0x42;
. d4 U/ ~/ G1 ]9 @2 A+ ^
buffer[2] = 0xe0;6 Y+ v' W8 l6 o! Q; q
: h5 q8 I, W8 M2 w
Buffer.BlockCopy(addresshash, 0, buffer, 3, addresshash.Length);9 ~4 Z; P. a( j3 \' B: A Z+ a
* h$ m2 u& y5 K, S- u
Buffer.BlockCopy(encryptedkey, 0, buffer, 7, encryptedkey.Length);* q. W8 j' H; i, V+ g( G
$ d* w' R: Z+ k* D
return buffer.Base58CheckEncode();
}/ K/ c* ]& ^, N% _* g
" n: {+ J2 h! N0 R. y1 q- c& _
}
可见SCrypt.DeriveKey方法参与了加密密钥的生成过程。后面解密也必然使用到了这个hash算法。所以该hash算法参与了加密过程,而加密密钥用AES256Encrypt生成。可以确定的是,使用该算法的逆过程,可以解密出密钥来,这个比WIF要安全。
Murmur3$ S& t- J% }8 Y" u) M
4 [% x9 h/ V3 ?3 B
MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。[1][2][3]由Austin Appleby在2008年发明,[4][5] 并出现了多个变种,[6] 都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。[7]$ V* D9 |1 L4 `4 X
; W' |+ k) \$ x* h, n
Murmur3特点
. r7 ]. i* l, o0 Z4 E; {* \
1.碰撞率低" T8 f s1 T* B# `- I3 s
2.计算速度快
- `, n8 C- I, A8 J: \
3.擅长大文件的hash7 m! k o" M' d H; C7 k
Neo中如何使用Murmur3
) S4 G. e5 k6 V8 s1 [% D5 ^
Neo中Murmur3
Murmur3的具体算法,以后再研究,现在大致知道,Neo用Murmur3生成key,也在BloomFilter中使用了。
8 p3 U/ ]3 c( B; _+ @7 |
RIPEMD-160
Neo中用这个算法来生成短一点的hash值,script hash就是用了这个算法。0 Y/ l2 m2 t3 f/ _3 W
// in neo-compiler/neo/neo/Core/Helper.cs
0 N$ ~! [" @4 j4 E7 W. d
public static UInt160 ToScriptHash(this byte[] script)
{
! L t' h, Z/ V6 }8 h( y
return new UInt160(Crypto.Default.Hash160(script));/ y A7 {% G4 o1 k
}
3 [$ @! f' \) f
RIPEMD-160算法的特点3 w8 B: [. T7 L7 q
" l( o6 g4 { V2 o2 a6 o
RIPEMD-160能表现出理想的 雪崩效应 (例如将 d 改成 c,即微小的变化就能产生一个完全不同的哈希值):" x1 ?' }$ S8 p0 q, S
2 d& h1 \. n3 R3 M) b q O& S& D9 s
加密算法体系# N" C$ K) R8 C# T- K3 h; t
现代加密算法的典型组件包括:加解密算法、加密密钥、解密密钥。其中,加解密算法自身是固定不变的,一般是公开可见的;密钥则往往每次不同,并且需要保护起来,一般来说,对同一种算法,密钥长度越长,则加密强度越大。7 h. Y6 Z% M7 P1 J
加密过程中,通过加密算法和加密密钥,对明文进行加密,获得密文。
' ~9 t! b+ ]# y$ a5 a! _. t
解密过程中,通过解密算法和解密密钥,对密文进行解密,获得明文。1 c# i$ {# }6 }( ~3 \) B: j
9 W [+ k0 f5 D( S8 Z, D8 T
根据加解密的密钥是否相同,算法可以分为对称加密(symmetric cryptography,又称公共密钥加密,common-key cryptography)和非对称加密(asymmetric cryptography,又称公钥加密,public-key cryptography)。两种模式适用于不同的需求,恰好形成互补,很多时候也可以组合使用,形成混合加密机制。 [2 Z7 H9 S1 @
并非所有加密算法的强度都可以从数学上进行证明。公认的高强度加密算法是在经过长时间各方面实践论证后,被大家所认可,不代表其不存在漏洞。但任何时候,自行发明加密算法都是一种不太明智的行为。9 H) S/ w: g0 S; w0 b. u, t- Z
对称加密
4 H& w; E! _+ |: A% I$ n
顾名思义,加解密的密钥是相同的。
对称加密优缺点
优点是加解密效率高(速度快,空间占用小),加密强度高。4 o" D: B9 V1 w% s$ O
. `( L5 A. v' @2 `% S
缺点是参与多方都需要持有密钥,一旦有人泄露则安全性被破坏;另外如何在不安全通道下分发密钥也是个问题。
适用于大量数据的加解密;不能用于签名场景;需要提前分发密钥。3 O6 k9 L7 r/ i
对称加密实现
对称密码从实现原理上可以分为两种:分组密码和序列密码。前者将明文切分为定长数据块作为加密单位,应用最为广泛。后者则只对一个字节进行加密,且密码不断变化,只用在一些特定领域,如数字媒介的加密等。* W! c; i# |& S! l% ]4 s4 b
代表算法包括 DES、3DES、AES、IDEA 等。! K) N, B8 J0 A4 U3 b) M1 J* c( A
1 V/ N9 S; _& w# Y/ x
DES(Data Encryption Standard):经典的分组加密算法,1977 年由美国联邦信息处理标准(FIPS)所采用 FIPS-46-3,将 64 位明文加密为 64 位的密文,其密钥长度为 56 位 + 8 位校验。现在已经很容易被暴力破解。
3DES:三重 DES 操作:加密 –> 解密 –> 加密,处理过程和加密强度优于 DES,但现在也被认为不够安全。: `/ w, }1 d+ @7 y- U0 Z
$ Q* K: r! `4 w) p: a
AES(Advanced Encryption Standard):美国国家标准研究所(NIST)采用取代 DES 成为对称加密实现的标准,1997~2000 年 NIST 从 15 个候选算法中评选 Rijndael 算法(由比利时密码学家 Joan Daemon 和 Vincent Rijmen 发明)作为 AES,标准为 FIPS-197。AES 也是分组算法,分组长度为 128、192、256 位三种。AES 的优势在于处理速度快,整个过程可以数学化描述,目前尚未有有效的破解手段。+ v1 z) j, |! C. q( T3 r
7 ~7 n/ ^1 {: G4 }6 [
注:分组加密每次只能处理固定长度的明文,因此过长的内容需要采用一定模式进行加密,《实用密码学》中推荐使用 密文分组链接(Cipher Block Chain,CBC)、计数器(Counter,CTR)模式。 `0 g5 f/ J f3 s
5 u- |9 {8 Y% i; Y- U2 ?
Neo中的AES W/ G f: a1 t9 t
在钱包的加解密中,使用了该算法。9 n$ |& x' D* g4 @
; Z' I) w. s# h+ Y- Q
下图的代码在/neo/Wallets/Wallet.cs中,NEP是neo enhancement proposal的意思。参数nep2就是符合这个格式的一个Neo钱包文件。
拿到私钥
具体的过程,后面再仔细研究分享出来。
; b9 f9 T# K8 }" @
非对称加密
8 f* D4 k" h! l0 { S
非对称加密是现代密码学历史上最为伟大的发明,可以很好的解决对称加密需要的提前分发密钥问题。顾名思义,加密密钥和解密密钥是不同的,分别称为公钥和私钥。公钥一般是公开的,人人可获取的,私钥一般是个人自己持有,不能被他人获取。
非对称加密优缺点+ l, K+ y) n, `
优点是公私钥分开,不安全通道也可使用。
& B& P6 S- q6 v/ Q$ d# L0 h
缺点是加解密速度慢,一般比对称加解密算法慢两到三个数量级;同时加密强度相比对称加密要差。
非对称加密代表算法) _6 ^+ ^, ^+ F& N! S) |4 I" D' W: U
* P+ K! R$ n6 z
非对称加密算法的安全性往往需要基于数学问题来保障,目前主要有基于大数质因子分解、离散对数、椭圆曲线等几种思路。
代表算法包括:RSA、ElGamal、椭圆曲线(Elliptic Curve Crytosystems,ECC)系列算法。
RSA:经典的公钥算法,1978 年由 Ron Rivest、Adi Shamir、Leonard Adleman 共同提出,三人于 2002 年获得图灵奖。算法利用了对大数进行质因子分解困难的特性,但目前还没有数学证明两者难度等价,或许存在未知算法在不进行大数分解的前提下解密。
7 E( C }9 N( l1 A# O5 @
Diffie-Hellman 密钥交换:基于离散对数无法快速求解,可以在不安全的通道上,双方协商一个公共密钥。
9 x$ ~7 e: u" S% J
ElGamal:由 Taher ElGamal 设计,利用了模运算下求离散对数困难的特性。被应用在 PGP 等安全工具中。* \* P9 u/ d( X, [" }. J
椭圆曲线算法(Elliptic curve cryptography,ECC):现代备受关注的算法系列,基于对椭圆曲线上特定点进行特殊乘法逆运算难以计算的特性。最早在 1985 年由 Neal Koblitz 和 Victor Miller 分别独立提出。ECC 系列算法一般被认为具备较高的安全性,但加解密计算过程往往比较费时。一般适用于签名场景或密钥协商,不适于大量数据的加解密。) Y( ~# j2 W( n3 C `
RSA 算法等已被认为不够安全,一般推荐采用椭圆曲线系列算法。
) p& i& ~9 U* P! X: X! v3 ]
Neo中的数字签名算法$ e6 [3 \: b3 K' z$ G
在Neo中,也使用了非对称加密算法,我们通过代码来看看是如何使用的。
- d2 C5 ^) D5 D1 S. i
public virtual WalletAccount Import(X509Certificate2 cert)8 O2 ~) ^1 X' t2 ^2 _
7 S, O: v8 j+ Q
{4 k' _* A( j7 t h: I& v5 ]7 X
4 a0 f7 s1 X4 ~. i
byte[] privateKey;
( [$ T8 L( F4 t: j/ L0 Z: K
using (ECDsa ecdsa = cert.GetECDsaPrivateKey())
{# f+ d1 X2 R. A6 k' d
! z* c/ W6 _( @
privateKey = ecdsa.ExportParameters(true).D;
}
0 z7 V' w3 d0 z/ U7 x4 m# l
WalletAccount account = CreateAccount(privateKey);) b) O- ]6 `& M3 D, \4 r& j R
Array.Clear(privateKey, 0, privateKey.Length);
return account;
}0 Z" `0 ?' A% a- H# b7 G! q
X509Certificate2是数字证书,和我们在https里面使用的是一样的,从里面拿出私钥后,创建钱包。 T" p. f( @0 k* m5 ]
总结' a; x4 M, d6 f# x$ }# O
. m, y1 V5 W$ @% z, y
目前只是简单的介绍了一下Neo中加密算法的使用情况,这些加密算法的原理和实现也是很有意思的,后面看看怎么实现的,再分享出来。
成为第一个吐槽的人