github.com/insolar/x-crypto@v0.0.0-20191031140942-75fab8a325f6/sha256/sha256.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
     6  // in FIPS 180-4.
     7  package sha256
     8  
     9  import (
    10  	"errors"
    11  	"github.com/insolar/x-crypto"
    12  	"hash"
    13  )
    14  
    15  func init() {
    16  	crypto.RegisterHash(crypto.SHA224, New224)
    17  	crypto.RegisterHash(crypto.SHA256, New)
    18  }
    19  
    20  // The size of a SHA256 checksum in bytes.
    21  const Size = 32
    22  
    23  // The size of a SHA224 checksum in bytes.
    24  const Size224 = 28
    25  
    26  // The blocksize of SHA256 and SHA224 in bytes.
    27  const BlockSize = 64
    28  
    29  const (
    30  	chunk     = 64
    31  	init0     = 0x6A09E667
    32  	init1     = 0xBB67AE85
    33  	init2     = 0x3C6EF372
    34  	init3     = 0xA54FF53A
    35  	init4     = 0x510E527F
    36  	init5     = 0x9B05688C
    37  	init6     = 0x1F83D9AB
    38  	init7     = 0x5BE0CD19
    39  	init0_224 = 0xC1059ED8
    40  	init1_224 = 0x367CD507
    41  	init2_224 = 0x3070DD17
    42  	init3_224 = 0xF70E5939
    43  	init4_224 = 0xFFC00B31
    44  	init5_224 = 0x68581511
    45  	init6_224 = 0x64F98FA7
    46  	init7_224 = 0xBEFA4FA4
    47  )
    48  
    49  // digest represents the partial evaluation of a checksum.
    50  type digest struct {
    51  	h     [8]uint32
    52  	x     [chunk]byte
    53  	nx    int
    54  	len   uint64
    55  	is224 bool // mark if this digest is SHA-224
    56  }
    57  
    58  const (
    59  	magic224      = "sha\x02"
    60  	magic256      = "sha\x03"
    61  	marshaledSize = len(magic256) + 8*4 + chunk + 8
    62  )
    63  
    64  func (d *digest) MarshalBinary() ([]byte, error) {
    65  	b := make([]byte, 0, marshaledSize)
    66  	if d.is224 {
    67  		b = append(b, magic224...)
    68  	} else {
    69  		b = append(b, magic256...)
    70  	}
    71  	b = appendUint32(b, d.h[0])
    72  	b = appendUint32(b, d.h[1])
    73  	b = appendUint32(b, d.h[2])
    74  	b = appendUint32(b, d.h[3])
    75  	b = appendUint32(b, d.h[4])
    76  	b = appendUint32(b, d.h[5])
    77  	b = appendUint32(b, d.h[6])
    78  	b = appendUint32(b, d.h[7])
    79  	b = append(b, d.x[:d.nx]...)
    80  	b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
    81  	b = appendUint64(b, d.len)
    82  	return b, nil
    83  }
    84  
    85  func (d *digest) UnmarshalBinary(b []byte) error {
    86  	if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
    87  		return errors.New("crypto/sha256: invalid hash state identifier")
    88  	}
    89  	if len(b) != marshaledSize {
    90  		return errors.New("crypto/sha256: invalid hash state size")
    91  	}
    92  	b = b[len(magic224):]
    93  	b, d.h[0] = consumeUint32(b)
    94  	b, d.h[1] = consumeUint32(b)
    95  	b, d.h[2] = consumeUint32(b)
    96  	b, d.h[3] = consumeUint32(b)
    97  	b, d.h[4] = consumeUint32(b)
    98  	b, d.h[5] = consumeUint32(b)
    99  	b, d.h[6] = consumeUint32(b)
   100  	b, d.h[7] = consumeUint32(b)
   101  	b = b[copy(d.x[:], b):]
   102  	b, d.len = consumeUint64(b)
   103  	d.nx = int(d.len) % chunk
   104  	return nil
   105  }
   106  
   107  func putUint32(x []byte, s uint32) {
   108  	_ = x[3]
   109  	x[0] = byte(s >> 24)
   110  	x[1] = byte(s >> 16)
   111  	x[2] = byte(s >> 8)
   112  	x[3] = byte(s)
   113  }
   114  
   115  func putUint64(x []byte, s uint64) {
   116  	_ = x[7]
   117  	x[0] = byte(s >> 56)
   118  	x[1] = byte(s >> 48)
   119  	x[2] = byte(s >> 40)
   120  	x[3] = byte(s >> 32)
   121  	x[4] = byte(s >> 24)
   122  	x[5] = byte(s >> 16)
   123  	x[6] = byte(s >> 8)
   124  	x[7] = byte(s)
   125  }
   126  
   127  func appendUint64(b []byte, x uint64) []byte {
   128  	var a [8]byte
   129  	putUint64(a[:], x)
   130  	return append(b, a[:]...)
   131  }
   132  
   133  func appendUint32(b []byte, x uint32) []byte {
   134  	var a [4]byte
   135  	putUint32(a[:], x)
   136  	return append(b, a[:]...)
   137  }
   138  
   139  func consumeUint64(b []byte) ([]byte, uint64) {
   140  	_ = b[7]
   141  	x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
   142  		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
   143  	return b[8:], x
   144  }
   145  
   146  func consumeUint32(b []byte) ([]byte, uint32) {
   147  	_ = b[3]
   148  	x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
   149  	return b[4:], x
   150  }
   151  
   152  func (d *digest) Reset() {
   153  	if !d.is224 {
   154  		d.h[0] = init0
   155  		d.h[1] = init1
   156  		d.h[2] = init2
   157  		d.h[3] = init3
   158  		d.h[4] = init4
   159  		d.h[5] = init5
   160  		d.h[6] = init6
   161  		d.h[7] = init7
   162  	} else {
   163  		d.h[0] = init0_224
   164  		d.h[1] = init1_224
   165  		d.h[2] = init2_224
   166  		d.h[3] = init3_224
   167  		d.h[4] = init4_224
   168  		d.h[5] = init5_224
   169  		d.h[6] = init6_224
   170  		d.h[7] = init7_224
   171  	}
   172  	d.nx = 0
   173  	d.len = 0
   174  }
   175  
   176  // New returns a new hash.Hash computing the SHA256 checksum. The Hash
   177  // also implements encoding.BinaryMarshaler and
   178  // encoding.BinaryUnmarshaler to marshal and unmarshal the internal
   179  // state of the hash.
   180  func New() hash.Hash {
   181  	d := new(digest)
   182  	d.Reset()
   183  	return d
   184  }
   185  
   186  // New224 returns a new hash.Hash computing the SHA224 checksum.
   187  func New224() hash.Hash {
   188  	d := new(digest)
   189  	d.is224 = true
   190  	d.Reset()
   191  	return d
   192  }
   193  
   194  func (d *digest) Size() int {
   195  	if !d.is224 {
   196  		return Size
   197  	}
   198  	return Size224
   199  }
   200  
   201  func (d *digest) BlockSize() int { return BlockSize }
   202  
   203  func (d *digest) Write(p []byte) (nn int, err error) {
   204  	nn = len(p)
   205  	d.len += uint64(nn)
   206  	if d.nx > 0 {
   207  		n := copy(d.x[d.nx:], p)
   208  		d.nx += n
   209  		if d.nx == chunk {
   210  			block(d, d.x[:])
   211  			d.nx = 0
   212  		}
   213  		p = p[n:]
   214  	}
   215  	if len(p) >= chunk {
   216  		n := len(p) &^ (chunk - 1)
   217  		block(d, p[:n])
   218  		p = p[n:]
   219  	}
   220  	if len(p) > 0 {
   221  		d.nx = copy(d.x[:], p)
   222  	}
   223  	return
   224  }
   225  
   226  func (d *digest) Sum(in []byte) []byte {
   227  	// Make a copy of d so that caller can keep writing and summing.
   228  	d0 := *d
   229  	hash := d0.checkSum()
   230  	if d0.is224 {
   231  		return append(in, hash[:Size224]...)
   232  	}
   233  	return append(in, hash[:]...)
   234  }
   235  
   236  func (d *digest) checkSum() [Size]byte {
   237  	len := d.len
   238  	// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
   239  	var tmp [64]byte
   240  	tmp[0] = 0x80
   241  	if len%64 < 56 {
   242  		d.Write(tmp[0 : 56-len%64])
   243  	} else {
   244  		d.Write(tmp[0 : 64+56-len%64])
   245  	}
   246  
   247  	// Length in bits.
   248  	len <<= 3
   249  	putUint64(tmp[:], len)
   250  	d.Write(tmp[0:8])
   251  
   252  	if d.nx != 0 {
   253  		panic("d.nx != 0")
   254  	}
   255  
   256  	var digest [Size]byte
   257  
   258  	putUint32(digest[0:], d.h[0])
   259  	putUint32(digest[4:], d.h[1])
   260  	putUint32(digest[8:], d.h[2])
   261  	putUint32(digest[12:], d.h[3])
   262  	putUint32(digest[16:], d.h[4])
   263  	putUint32(digest[20:], d.h[5])
   264  	putUint32(digest[24:], d.h[6])
   265  	if !d.is224 {
   266  		putUint32(digest[28:], d.h[7])
   267  	}
   268  
   269  	return digest
   270  }
   271  
   272  // Sum256 returns the SHA256 checksum of the data.
   273  func Sum256(data []byte) [Size]byte {
   274  	var d digest
   275  	d.Reset()
   276  	d.Write(data)
   277  	return d.checkSum()
   278  }
   279  
   280  // Sum224 returns the SHA224 checksum of the data.
   281  func Sum224(data []byte) (sum224 [Size224]byte) {
   282  	var d digest
   283  	d.is224 = true
   284  	d.Reset()
   285  	d.Write(data)
   286  	sum := d.checkSum()
   287  	copy(sum224[:], sum[:Size224])
   288  	return
   289  }