Minio解密逻辑

data, err := DecryptData(adm.getSecretKey(), resp.Body)

func DecryptData(password string, data io.Reader) ([]byte, error) {
   var (
      salt  [32]byte
      id    [1]byte
      nonce [8]byte // This depends on the AEAD but both used ciphers have the same nonce length.
   )

   if _, err := io.ReadFull(data, salt[:]); err != nil {
      return nil, err
   }
   if _, err := io.ReadFull(data, id[:]); err != nil {
      return nil, err
   }
   if _, err := io.ReadFull(data, nonce[:]); err != nil {
      return nil, err
   }

   key := idKey([]byte(password), salt[:], nil, nil, 32)
   var (
      err    error
      stream *sio.Stream
   )
   switch id[0] {
   case aesGcm:
      stream, err = sio.AES_256_GCM.Stream(key)
   case c20p1305:
      stream, err = sio.ChaCha20Poly1305.Stream(key)
   default:
      err = errors.New("madmin: invalid AEAD algorithm ID")
   }
   if err != nil {
      return nil, err
   }

   enBytes, err := ioutil.ReadAll(stream.DecryptReader(data, nonce[:], nil))
   if err != nil {
      if err == sio.NotAuthentic {
         return enBytes, ErrMaliciousData
      }
   }
   return enBytes, err
}

idKey = argon2.NewIDKey(1, 64*1024, 4)


// NewIDKey returns an argon2 PBKDF backend by sync.Pool
func NewIDKey(time, memory uint32, threads uint8) func([]byte, []byte, []byte, []byte, uint32) []byte {
   if time < 1 {
      panic("argon2: number of rounds too small")
   }
   if threads < 1 {
      panic("argon2: parallelism degree too low")
   }

   hashMemory := memory

   memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
   if memory < 2*syncPoints*uint32(threads) {
      memory = 2 * syncPoints * uint32(threads)
   }

   pool := sync.Pool{
      New: func() interface{} {
         b := make([]block, memory)
         return &b
      },
   }

   return func(password, salt, secret, data []byte, keyLen uint32) []byte {
      B := pool.Get().(*[]block)
      defer func() {
         clearBlocks(*B)
         pool.Put(B)
      }()

      h0 := initHash(password, salt, secret, data, time, hashMemory, uint32(threads), keyLen, argon2id)
      B1 := initBlocks(&h0, *B, uint32(threads))
      processBlocks(B1, time, memory, uint32(threads), argon2id)
      return extractKey(B1, memory, uint32(threads), keyLen)
   }
}

sync.Pool 减少GC 提供了对象重用的机制 并发安全


func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte {
   var (
      h0     [blake2b.Size + 8]byte
      params [24]byte
      tmp    [4]byte
   )

   b2, _ := blake2b.New512(nil)
   binary.LittleEndian.PutUint32(params[0:4], threads)
   binary.LittleEndian.PutUint32(params[4:8], keyLen)
   binary.LittleEndian.PutUint32(params[8:12], memory)
   binary.LittleEndian.PutUint32(params[12:16], time)
   binary.LittleEndian.PutUint32(params[16:20], uint32(Version))
   binary.LittleEndian.PutUint32(params[20:24], uint32(mode))
   b2.Write(params[:])
   binary.LittleEndian.PutUint32(tmp[:], uint32(len(password)))
   b2.Write(tmp[:])
   b2.Write(password)
   binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt)))
   b2.Write(tmp[:])
   b2.Write(salt)
   binary.LittleEndian.PutUint32(tmp[:], uint32(len(key)))
   b2.Write(tmp[:])
   b2.Write(key)
   binary.LittleEndian.PutUint32(tmp[:], uint32(len(data)))
   b2.Write(tmp[:])
   b2.Write(data)
   b2.Sum(h0[:0])
   return h0
}

func initBlocks(h0 *[blake2b.Size + 8]byte, blocks []block, threads uint32) []block {
   var block0 [1024]byte
   B := blocks
   for lane := uint32(0); lane < threads; lane++ {
      j := lane * (uint32(len(B)) / threads)
      binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane)

      binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0)
      blake2bHash(block0[:], h0[:])
      for i := range B[j+0] {
         B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:])
      }

      binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1)
      blake2bHash(block0[:], h0[:])
      for i := range B[j+1] {
         B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:])
      }
   }
   return B
}

func processBlocks(B []block, time, memory, threads uint32, mode int) {
   lanes := memory / threads
   segments := lanes / syncPoints

   processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) {
      var addresses, in, zero block
      if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
         in[0] = uint64(n)
         in[1] = uint64(lane)
         in[2] = uint64(slice)
         in[3] = uint64(memory)
         in[4] = uint64(time)
         in[5] = uint64(mode)
      }

      index := uint32(0)
      if n == 0 && slice == 0 {
         index = 2 // we have already generated the first two blocks
         if mode == argon2i || mode == argon2id {
            in[6]++
            processBlock(&addresses, &in, &zero)
            processBlock(&addresses, &addresses, &zero)
         }
      }

      offset := lane*lanes + slice*segments + index
      var random uint64
      for index < segments {
         prev := offset - 1
         if index == 0 && slice == 0 {
            prev += lanes // last block in lane
         }
         if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
            if index%blockLength == 0 {
               in[6]++
               processBlock(&addresses, &in, &zero)
               processBlock(&addresses, &addresses, &zero)
            }
            random = addresses[index%blockLength]
         } else {
            random = B[prev][0]
         }
         newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index)
         processBlockXOR(&B[offset], &B[prev], &B[newOffset])
         index, offset = index+1, offset+1
      }
      wg.Done()
   }

   for n := uint32(0); n < time; n++ {
      for slice := uint32(0); slice < syncPoints; slice++ {
         var wg sync.WaitGroup
         for lane := uint32(0); lane < threads; lane++ {
            wg.Add(1)
            go processSegment(n, slice, lane, &wg)
         }
         wg.Wait()
      }
   }

}

func extractKey(B []block, memory, threads, keyLen uint32) []byte {
   lanes := memory / threads
   for lane := uint32(0); lane < threads-1; lane++ {
      for i, v := range B[(lane*lanes)+lanes-1] {
         B[memory-1][i] ^= v
      }
   }

   var block [1024]byte
   for i, v := range B[memory-1] {
      binary.LittleEndian.PutUint64(block[i*8:], v)
   }
   key := make([]byte, keyLen)
   blake2bHash(key, block[:])
   return key
}
func blake2bHash(out []byte, in []byte) {
   var b2 hash.Hash
   if n := len(out); n < blake2b.Size {
      b2, _ = blake2b.New(n, nil)
   } else {
      b2, _ = blake2b.New512(nil)
   }

   var buffer [blake2b.Size]byte
   binary.LittleEndian.PutUint32(buffer[:4], uint32(len(out)))
   b2.Write(buffer[:4])
   b2.Write(in)

   if len(out) <= blake2b.Size {
      b2.Sum(out[:0])
      return
   }

   outLen := len(out)
   b2.Sum(buffer[:0])
   b2.Reset()
   copy(out, buffer[:32])
   out = out[32:]
   for len(out) > blake2b.Size {
      b2.Write(buffer[:])
      b2.Sum(buffer[:0])
      copy(out, buffer[:32])
      out = out[32:]
      b2.Reset()
   }

   if outLen%blake2b.Size > 0 { // outLen > 64
      r := ((outLen + 31) / 32) - 2 // ⌈τ /32⌉-2
      b2, _ = blake2b.New(outLen-32*r, nil)
   }
   b2.Write(buffer[:])
   b2.Sum(out[:0])
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值