github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/encryption/encryption.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:44</date>
    10  //</624450118485020672>
    11  
    12  
    13  package encryption
    14  
    15  import (
    16  	"crypto/rand"
    17  	"encoding/binary"
    18  	"fmt"
    19  	"hash"
    20  	"sync"
    21  )
    22  
    23  const KeyLength = 32
    24  
    25  type Key []byte
    26  
    27  type Encryption interface {
    28  	Encrypt(data []byte) ([]byte, error)
    29  	Decrypt(data []byte) ([]byte, error)
    30  }
    31  
    32  type encryption struct {
    33  key      Key              //加密密钥(hashsize bytes long)
    34  keyLen   int              //密钥长度=分组密码块的长度
    35  padding  int              //如果大于0,加密会将数据填充到此
    36  initCtr  uint32           //用于计数器模式块密码的初始计数器
    37  hashFunc func() hash.Hash //哈希构造函数函数
    38  }
    39  
    40  //new构造新的加密/解密程序
    41  func New(key Key, padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
    42  	return &encryption{
    43  		key:      key,
    44  		keyLen:   len(key),
    45  		padding:  padding,
    46  		initCtr:  initCtr,
    47  		hashFunc: hashFunc,
    48  	}
    49  }
    50  
    51  //Encrypt加密数据并在指定时进行填充
    52  func (e *encryption) Encrypt(data []byte) ([]byte, error) {
    53  	length := len(data)
    54  	outLength := length
    55  	isFixedPadding := e.padding > 0
    56  	if isFixedPadding {
    57  		if length > e.padding {
    58  			return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
    59  		}
    60  		outLength = e.padding
    61  	}
    62  	out := make([]byte, outLength)
    63  	e.transform(data, out)
    64  	return out, nil
    65  }
    66  
    67  //decrypt解密数据,如果使用填充,调用方必须知道原始长度并截断
    68  func (e *encryption) Decrypt(data []byte) ([]byte, error) {
    69  	length := len(data)
    70  	if e.padding > 0 && length != e.padding {
    71  		return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
    72  	}
    73  	out := make([]byte, length)
    74  	e.transform(data, out)
    75  	return out, nil
    76  }
    77  
    78  //
    79  func (e *encryption) transform(in, out []byte) {
    80  	inLength := len(in)
    81  	wg := sync.WaitGroup{}
    82  	wg.Add((inLength-1)/e.keyLen + 1)
    83  	for i := 0; i < inLength; i += e.keyLen {
    84  		l := min(e.keyLen, inLength-i)
    85  //每段调用转换(异步)
    86  		go func(i int, x, y []byte) {
    87  			defer wg.Done()
    88  			e.Transcrypt(i, x, y)
    89  		}(i/e.keyLen, in[i:i+l], out[i:i+l])
    90  	}
    91  //如果出局时间较长,则补上其余部分。
    92  	pad(out[inLength:])
    93  	wg.Wait()
    94  }
    95  
    96  //用于分段转换
    97  //如果输入短于输出,则使用填充
    98  func (e *encryption) Transcrypt(i int, in []byte, out []byte) {
    99  //带计数器的第一个哈希键(初始计数器+I)
   100  	hasher := e.hashFunc()
   101  	hasher.Write(e.key)
   102  
   103  	ctrBytes := make([]byte, 4)
   104  	binary.LittleEndian.PutUint32(ctrBytes, uint32(i)+e.initCtr)
   105  	hasher.Write(ctrBytes)
   106  
   107  	ctrHash := hasher.Sum(nil)
   108  	hasher.Reset()
   109  
   110  //第二轮哈希选择披露
   111  	hasher.Write(ctrHash)
   112  	segmentKey := hasher.Sum(nil)
   113  	hasher.Reset()
   114  
   115  //输入的XOR字节正常运行时间长度(输出必须至少与之相同)
   116  	inLength := len(in)
   117  	for j := 0; j < inLength; j++ {
   118  		out[j] = in[j] ^ segmentKey[j]
   119  	}
   120  //如果超出长度,则插入填充
   121  	pad(out[inLength:])
   122  }
   123  
   124  func pad(b []byte) {
   125  	l := len(b)
   126  	for total := 0; total < l; {
   127  		read, _ := rand.Read(b[total:])
   128  		total += read
   129  	}
   130  }
   131  
   132  //GenerateRandomKey生成长度为l的随机键
   133  func GenerateRandomKey(l int) Key {
   134  	key := make([]byte, l)
   135  	var total int
   136  	for total < l {
   137  		read, _ := rand.Read(key[total:])
   138  		total += read
   139  	}
   140  	return key
   141  }
   142  
   143  func min(x, y int) int {
   144  	if x < y {
   145  		return x
   146  	}
   147  	return y
   148  }
   149