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.
 
 
 
 

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