You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

164 regels
3.4 KiB

  1. // This is initial implementation of CTR_DRBG with AES-256. Code is tested
  2. // and functionaly correct. Nevertheless it will be changed
  3. //
  4. // TODO: Following things still need to be done
  5. // * Add other AES key lengts
  6. // * Validate sizes from table 3 of SP800-90A
  7. // * Improve reseeding so that code returns an error when reseed is needed
  8. // * Add case with derivation function (maybe)
  9. // * Code cleanup
  10. // * Implement benchmark
  11. // * Add rest of the test vectors from CAVP
  12. package drbg
  13. import (
  14. "github.com/henrydcase/nobs/drbg/internal/aes"
  15. "github.com/henrydcase/nobs/utils"
  16. )
  17. // Constants below correspond to AES-256, which is currently
  18. // the only block cipher supported.
  19. const (
  20. BlockLen = 16
  21. KeyLen = 32
  22. SeedLen = BlockLen + KeyLen
  23. )
  24. type CtrDrbg struct {
  25. v [BlockLen]byte
  26. key [KeyLen]byte
  27. counter uint
  28. strength uint
  29. resistance bool
  30. blockEnc aes.IAES
  31. tmpBlk [3 * BlockLen]byte
  32. }
  33. func NewCtrDrbg() *CtrDrbg {
  34. if utils.X86.HasAES {
  35. return &CtrDrbg{blockEnc: &aes.AESAsm{}}
  36. }
  37. return &CtrDrbg{blockEnc: &aes.AES{}}
  38. }
  39. func (c *CtrDrbg) inc() {
  40. for i := BlockLen - 1; i >= 0; i-- {
  41. if c.v[i] == 0xff {
  42. c.v[i] = 0x00
  43. } else {
  44. c.v[i]++
  45. break
  46. }
  47. }
  48. }
  49. func (c *CtrDrbg) Init(entropy, personalization []byte) bool {
  50. var lsz int
  51. var seedBuf [SeedLen]byte
  52. // Minimum entropy input (SP800-90A, 10.2.1)
  53. if len(entropy) < int(c.strength/8) {
  54. return false
  55. }
  56. // Security strength for AES-256 as per SP800-57, 5.6.1
  57. c.strength = 256
  58. lsz = len(entropy)
  59. if lsz > SeedLen {
  60. lsz = SeedLen
  61. }
  62. copy(seedBuf[:], entropy[:lsz])
  63. lsz = len(personalization)
  64. if lsz > SeedLen {
  65. lsz = SeedLen
  66. }
  67. for i := 0; i < lsz; i++ {
  68. seedBuf[i] ^= personalization[i]
  69. }
  70. c.blockEnc.SetKey(c.key[:])
  71. c.update(seedBuf[:])
  72. c.counter = 1
  73. return true
  74. }
  75. func (c *CtrDrbg) update(data []byte) {
  76. if len(data) != SeedLen {
  77. panic("Provided data is not equal to strength/8")
  78. }
  79. // deliberatelly not using len(c.tmpBlk)
  80. for i := 0; i < 3*BlockLen; i += BlockLen {
  81. c.inc()
  82. c.blockEnc.SetKey(c.key[:])
  83. c.blockEnc.Encrypt(c.tmpBlk[i:], c.v[:])
  84. }
  85. for i := 0; i < 3*BlockLen; i++ {
  86. c.tmpBlk[i] ^= data[i]
  87. }
  88. copy(c.key[:], c.tmpBlk[:KeyLen])
  89. copy(c.v[:], c.tmpBlk[KeyLen:])
  90. }
  91. func (c *CtrDrbg) Reseed(entropy, data []byte) {
  92. var seedBuf [SeedLen]byte
  93. var lsz int
  94. lsz = len(entropy)
  95. if lsz > SeedLen {
  96. lsz = SeedLen
  97. }
  98. copy(seedBuf[:], entropy[:lsz])
  99. lsz = len(data)
  100. if lsz > SeedLen {
  101. lsz = SeedLen
  102. }
  103. for i := 0; i < lsz; i++ {
  104. seedBuf[i] ^= data[i]
  105. }
  106. c.update(seedBuf[:])
  107. c.counter = 1
  108. }
  109. func (c *CtrDrbg) ReadWithAdditionalData(out, ad []byte) (n int, err error) {
  110. var seedBuf [SeedLen]byte
  111. // TODO: check reseed_counter > reseed_interval
  112. if len(ad) > 0 {
  113. // pad additional data with zeros if needed
  114. copy(seedBuf[:], ad)
  115. c.update(seedBuf[:])
  116. }
  117. // Number of blocks to write minus last one
  118. blocks := len(out) / BlockLen
  119. for i := 0; i < blocks; i++ {
  120. c.inc()
  121. c.blockEnc.SetKey(c.key[:])
  122. c.blockEnc.Encrypt(out[i*BlockLen:], c.v[:])
  123. }
  124. // Copy remainder - case for out being not block aligned
  125. c.blockEnc.Encrypt(c.tmpBlk[:], c.v[:])
  126. copy(out[blocks*BlockLen:], c.tmpBlk[:len(out)%BlockLen])
  127. c.update(seedBuf[:])
  128. c.counter += 1
  129. return len(out), nil
  130. }
  131. // Read reads data from DRBG. Size of data is determined by
  132. // out buffer.
  133. func (c *CtrDrbg) Read(out []byte) (n int, err error) {
  134. return c.ReadWithAdditionalData(out, nil)
  135. }