// Tweak generates a new tweak from the mode, hash, salt length (in // bytes), and any additional data. It provides additional information // that will complicate an attacker's efforts, and allows a system to // differentiate between different uses of the Catena function's output. func Tweak(mode byte, H hash.Hash, saltLen int, ad []byte) ([]byte, error) { if mode != ModePassHash && mode != ModeKeyDerivation { return nil, ErrInvalidTweakMode } hashLen := H.Size() tweakLen := 5 + hashLen var t = make([]byte, 1, tweakLen) t[0] = mode var tmp uint16 = uint16(H.Size() * 8) high := byte(tmp >> 8) low := byte(tmp << 8 >> 8) t = append(t, high) t = append(t, low) tmp = uint16(saltLen * 8) high = byte(tmp >> 8) low = byte(tmp << 8 >> 8) t = append(t, high) t = append(t, low) H.Reset() H.Write(ad) t = append(t, H.Sum(nil)...) H.Reset() return t, nil }
func Encode(k int, h hash.Hash, value []byte, output int) (enc []byte, s [][]byte) { s0 := make([]byte, h.Size()) n := len(value) blockcount := n / k s = make([][]byte, blockcount) for i := 0; i < blockcount; i++ { h.Reset() if i == 0 { h.Write(s0) } else { h.Write(s[i-1]) } h.Write(value[i*k : (i+1)*k]) s[i] = h.Sum(make([]byte, 0, h.Size())) } rng := make([](*RNG), len(s)) for i := 0; i < len(s); i++ { rng[i] = NewRNG(h, s[i]) } enc = make([]byte, output) for i := 0; i < output; i++ { enc[i] = rng[i%blockcount].Next() } return }
// decode uses the given block cipher (in CTR mode) to decrypt the // data, and validate the hash. If hash validation fails, an error is // returned. func decode(block cipher.Block, hmac hash.Hash, ciphertext []byte) ([]byte, error) { if len(ciphertext) < 2*block.BlockSize()+hmac.Size() { return nil, LenError } receivedHmac := ciphertext[len(ciphertext)-hmac.Size():] ciphertext = ciphertext[:len(ciphertext)-hmac.Size()] hmac.Write(ciphertext) if subtle.ConstantTimeCompare(hmac.Sum(nil), receivedHmac) != 1 { return nil, HashError } // split the iv and session bytes iv := ciphertext[len(ciphertext)-block.BlockSize():] session := ciphertext[:len(ciphertext)-block.BlockSize()] stream := cipher.NewCTR(block, iv) stream.XORKeyStream(session, session) // skip past the iv session = session[block.BlockSize():] return session, nil }
// DeriveConcatKDF implements NIST SP 800-56A Concatenation Key Derivation Function. Derives // key material of keydatalen bits size given Z (sharedSecret), OtherInfo (AlgorithmID | // PartyUInfo | PartyVInfo | SuppPubInfo | SuppPrivInfo) and hash function func DeriveConcatKDF(keydatalen int, sharedSecret, algId, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo []byte, h hash.Hash) []byte { otherInfo := arrays.Concat(algId, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo) keyLenBytes := keydatalen >> 3 reps := int(math.Ceil(float64(keyLenBytes) / float64(h.Size()))) if reps > MaxInt { panic("kdf.DeriveConcatKDF: too much iterations (more than 2^32-1).") } dk := make([]byte, 0, keyLenBytes) for counter := 1; counter <= reps; counter++ { h.Reset() counterBytes := arrays.UInt32ToBytes(uint32(counter)) h.Write(counterBytes) h.Write(sharedSecret) h.Write(otherInfo) dk = h.Sum(dk) } return dk[:keyLenBytes] }
// EncryptOAEP encrypts the given message with RSA-OAEP. // The message must be no longer than the length of the public modulus less // twice the hash length plus 2. func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) { hash.Reset() k := (pub.N.Len() + 7) / 8 if len(msg) > k-2*hash.Size()-2 { err = MessageTooLongError{} return } hash.Write(label) lHash := hash.Sum() hash.Reset() em := make([]byte, k) seed := em[1 : 1+hash.Size()] db := em[1+hash.Size():] copy(db[0:hash.Size()], lHash) db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) _, err = io.ReadFull(rand, seed) if err != nil { return } mgf1XOR(db, hash, seed) mgf1XOR(seed, hash, db) m := new(big.Int) m.SetBytes(em) c := encrypt(new(big.Int), pub, m) out = c.Bytes() return }
func (s *descbc) Decrypt(salt []byte, algo, usage int, data []byte) ([]byte, error) { var h hash.Hash switch algo { case cryptDesCbcMd5: h = md5.New() case cryptDesCbcMd4: h = md4.New() default: return nil, ErrProtocol } if (len(data) & 7) != 0 { return nil, ErrProtocol } iv := [8]byte{} b, _ := des.NewCipher(s.key) c := cipher.NewCBCDecrypter(b, iv[:]) c.CryptBlocks(data, data) chk := make([]byte, h.Size()) h.Write(data[:8]) h.Write(chk) // Just need h.Size() zero bytes instead of the checksum h.Write(data[8+len(chk):]) h.Sum(chk[:0]) if subtle.ConstantTimeCompare(chk, data[8:8+len(chk)]) != 1 { return nil, ErrProtocol } return data[8+len(chk):], nil }
func NewHashAppendReader(r io.Reader, h hash.Hash) *HashAppendReader { return &HashAppendReader{ h: h, r: io.TeeReader(r, h), sum: make([]byte, 0, h.Size()), } }
// jssdk 支付签名, signType 只支持 "MD5", "SHA1", 传入其他的值会 panic. func JsapiSign(appId, timeStamp, nonceStr, packageStr, signType string, apiKey string) string { var h hash.Hash switch signType { case "MD5": h = md5.New() case "SHA1": h = sha1.New() default: panic("unsupported signType") } bufw := bufio.NewWriterSize(h, 128) // appId // nonceStr // package // signType // timeStamp bufw.WriteString("appId=") bufw.WriteString(appId) bufw.WriteString("&nonceStr=") bufw.WriteString(nonceStr) bufw.WriteString("&package=") bufw.WriteString(packageStr) bufw.WriteString("&signType=") bufw.WriteString(signType) bufw.WriteString("&timeStamp=") bufw.WriteString(timeStamp) bufw.WriteString("&key=") bufw.WriteString(apiKey) bufw.Flush() signature := make([]byte, hex.EncodedLen(h.Size())) hex.Encode(signature, h.Sum(nil)) return string(bytes.ToUpper(signature)) }
func NewRNG(h hash.Hash, seed []byte) (r *RNG) { r = new(RNG) r.i = 3610617884 r.h = h r.buffer = make([]byte, 0, h.Size()) r.seed = seed return }
func GenSessionId() string { var h hash.Hash = sessHash() h.Write(GenRandomBytes(sessEnthropy)) h.Write([]byte(strconv.FormatInt(time.Now().Unix(), 10))) id := make([]byte, 0, h.Size()) id = h.Sum(id) return base64.StdEncoding.EncodeToString(id) }
func NewHashAppendWriter(w io.Writer, h hash.Hash) *HashAppendWriter { return &HashAppendWriter{ h: h, w: io.MultiWriter(w, h), origWr: w, sum: make([]byte, 0, h.Size()), } }
// GoId creates a UUID object based on timestamps and a hash. // It will truncate any bytes past the length of the initial hash. // This creates a UUID based on a Namespace, UniqueName and an existing // hash. func GoId(pNs UUID, pName UniqueName, pHash hash.Hash) UUID { o := new(UUIDStruct) o.size = pHash.Size() Digest(o, pNs, pName, pHash) now := currentUUIDTimestamp() sequence := uint16(seed.Int()) & 0x3FFF return formatGoId(o, now, 15, ReservedFuture, sequence) }
// this is the function which calculates the HTOP code func calculateToken(counter []byte, digits int, h hash.Hash) string { h.Write(counter) hashResult := h.Sum(nil) result := truncateHash(hashResult, h.Size()) mod := int32(result % int64(math.Pow10(digits))) fmtStr := fmt.Sprintf("%%0%dd", digits) return fmt.Sprintf(fmtStr, mod) }
func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) { h.Reset() var p [1]byte p[0] = prefix h.Write(p[:]) h.Write(in) if len(out) == h.Size() { h.Sum(out[:0]) } else { digest := h.Sum(nil) copy(out, digest) } }
func testWrite(msg string, t *testing.T, h hash.Hash, c *Config) { var msg1 []byte msg0 := make([]byte, 64) for i := range msg0 { h.Write(msg0[:i]) msg1 = append(msg1, msg0[:i]...) } tag0 := h.Sum(nil) tag1 := Sum(msg1, h.Size(), c) if !bytes.Equal(tag0, tag1) { t.Fatalf("%s\nSum differ from Sum\n Sum: %s \n skein.Sum: %s", msg, hex.EncodeToString(tag0), hex.EncodeToString(tag1)) } }
func benchmarkKB(b *testing.B, h hash.Hash) { b.SetBytes(1024) data := make([]byte, 1024) for i := range data { data[i] = byte(i) } in := make([]byte, 0, h.Size()) b.ResetTimer() for i := 0; i < b.N; i++ { h.Reset() h.Write(data) h.Sum(in) } }
// New returns a new HMAC hash using the given hash and key. func New(h hash.Hash, key []byte) hash.Hash { if len(key) > padSize { // If key is too big, hash it. h.Write(key) key = h.Sum() } hm := new(hmac) hm.inner = h hm.size = h.Size() hm.key = make([]byte, len(key)) for i, k := range key { hm.key[i] = k } hm.tmp = make([]byte, padSize+hm.size) hm.Reset() return hm }
func benchmarkHash(b *testing.B, h hash.Hash, l int) { m := make([]byte, l) tag := make([]byte, 0, h.Size()) b.SetBytes(int64(l)) b.ResetTimer() for i := 0; i < b.N; i++ { h.Reset() h.Write(m[:l/4]) h.Write(m[l/4 : l/2]) h.Write(m[l/2 : 3*l/4]) h.Write(m[3*l/4:]) h.Sum(tag) } }
// EncryptOAEP encrypts the given message with RSA-OAEP. // The message must be no longer than the length of the public modulus less // twice the hash length plus 2. func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { if err := checkPub(pub); err != nil { return nil, err } hash.Reset() k := (pub.N.BitLen() + 7) / 8 if len(msg) > k-2*hash.Size()-2 { err = ErrMessageTooLong return } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() em := make([]byte, k) seed := em[1 : 1+hash.Size()] db := em[1+hash.Size():] copy(db[0:hash.Size()], lHash) db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) _, err = io.ReadFull(random, seed) if err != nil { return } mgf1XOR(db, hash, seed) mgf1XOR(seed, hash, db) m := new(big.Int) m.SetBytes(em) c := encrypt(new(big.Int), pub, m) out = c.Bytes() if len(out) < k { // If the output is too small, we need to left-pad with zeros. t := make([]byte, k) copy(t[k-len(out):], out) out = t } return }
// Encode a message with fixed salt, return the encoded message and random salt func Encode(hash hash.Hash, msg, salt []byte) ([]byte, []byte, error) { if hash == nil { hash = sha256.New() } rand, err := rand.B.Alphanumeric(hash.Size()) if err != nil { return nil, nil, err } return SaltEncode(hash, msg, salt, rand), rand, err }
// Creates all the non-leaf nodes for a certain height. The number of nodes // is calculated to be 1/2 the number of nodes in the lower rung. The newly // created nodes will reference their Left and Right children. // Returns the number of nodes added to current func (self *Tree) generateNodeLevel(below []Node, current []Node, h hash.Hash) (uint64, error) { h.Reset() size := h.Size() data := make([]byte, size*2) end := (len(below) + (len(below) % 2)) / 2 for i := 0; i < end; i++ { // Concatenate the two children hashes and hash them, if both are // available, otherwise reuse the hash from the lone left node node := Node{} ileft := 2 * i iright := 2*i + 1 left := &below[ileft] var right *Node = nil if len(below) > iright { right = &below[iright] } if right == nil { b := data[:size] copy(b, left.Hash) node = Node{Hash: b} } else { copy(data[:size], below[ileft].Hash) copy(data[size:], below[iright].Hash) var err error node, err = NewNode(h, data) if err != nil { return 0, err } } // Point the new node to its children and save node.Left = left node.Right = right current[i] = node // Reset the data slice data = data[:] } return uint64(end), nil }
func testIntegrity(t *testing.T, h hash.Hash) { data := []byte{'1', '2', 3, 4, 5} h.Write(data) sum := h.Sum() if size := h.Size(); size != len(sum) { t.Fatalf("Size()=%d but len(Sum())=%d", size, len(sum)) } if a := h.Sum(); !bytes.Equal(sum, a) { t.Fatalf("first Sum()=0x%x, second Sum()=0x%x", sum, a) } h.Reset() h.Write(data) if a := h.Sum(); !bytes.Equal(sum, a) { t.Fatalf("Sum()=0x%x, but after Reset() Sum()=0x%x", sum, a) } h.Reset() h.Write(data[:2]) h.Write(data[2:]) if a := h.Sum(); !bytes.Equal(sum, a) { t.Fatalf("Sum()=0x%x, but with partial writes, Sum()=0x%x", sum, a) } switch h.Size() { case 4: sum32 := h.(hash.Hash32).Sum32() if sum32 != binary.BigEndian.Uint32(sum) { t.Fatalf("Sum()=0x%x, but Sum32()=0x%x", sum, sum32) } case 8: sum64 := h.(hash.Hash64).Sum64() if sum64 != binary.BigEndian.Uint64(sum) { t.Fatalf("Sum()=0x%x, but Sum64()=0x%x", sum, sum64) } } }
func (s *descbc) Encrypt(salt []byte, usage int, data ...[]byte) []byte { var h hash.Hash switch s.etype { case cryptDesCbcMd5: h = md5.New() case cryptDesCbcMd4: h = md4.New() default: panic("") } outsz := 8 + h.Size() for _, d := range data { outsz += len(d) } outsz = (outsz + 7) &^ 7 out := make([]byte, outsz) io.ReadFull(rand.Reader, out[:8]) v := out[8+h.Size():] for _, d := range data { n := copy(v, d) v = v[n:] } h.Write(out) h.Sum(out[:8]) iv := [8]byte{} b, _ := des.NewCipher(s.key) c := cipher.NewCBCEncrypter(b, iv[:]) c.CryptBlocks(out, out) return out }
// SendFile reads a file from disk and streams it to a receiver across a // MessageStream. If there are sufficient bytes in the keys (at least // hmacKeySize+aesKeySize), then it will attempt to check the integrity of the // file with HMAC-SHA256 and decrypt it with AES-CTR-128. func SendFile(ms util.MessageStream, dir string, filename string, keys []byte) error { fullpath := path.Join(dir, filename) fileInfo, err := os.Stat(fullpath) if err != nil { return fmt.Errorf("in SendFile: no file '%s' found: %s", fullpath, err) } file, err := os.Open(fullpath) if err != nil { return fmt.Errorf("in SendFile: can't open file '%s': %s", fullpath, err) } defer file.Close() // This encryption scheme uses AES-CTR with HMAC-SHA256 for integrity // protection. var hm hash.Hash var ctr cipher.Stream iv := make([]byte, ivSize) hasKeys := len(keys) >= minKeySize // The variable "left" gives the total number of bytes left to read from // the (maybe encrypted) file. left := fileInfo.Size() buf := make([]byte, bufferSize) if hasKeys { dec, err := aes.NewCipher(keys[:aesKeySize]) if err != nil || dec == nil { return fmt.Errorf("can't create AES cipher in SendFile: %s", err) } if _, err := file.Read(iv); err != nil { return err } // Remove the IV from the number of remaining bytes to decrypt. left = left - ivSize // Take all the remaining key bytes for the HMAC key. hm = hmac.New(sha256.New, keys[aesKeySize:]) hmacSize := hm.Size() // The HMAC input starts with the IV. hm.Write(iv) ctr = cipher.NewCTR(dec, iv) if ctr == nil { return fmt.Errorf("can't create AES-CTR encryption") } // Remove the HMAC-SHA256 output from the bytes to check. left = left - int64(hmacSize) // Secure decryption in this case requires reading the file // twice: once to check the MAC, and once to decrypt the bytes. // The MAC must be checked before *any* decryption occurs and // before *any* decrypted bytes are sent to the receiver. for { // Figure out how many bytes to read on this iteration. readSize := int64(bufferSize) final := false if left <= bufferSize { readSize = left final = true } // Read the (maybe encrypted) bytes from the file. n, err := file.Read(buf[:readSize]) if err != nil { return err } left = left - int64(n) hm.Write(buf[:n]) if final { break } } computed := hm.Sum(nil) original := buf[:hmacSize] // Read the file's version of the HMAC and check it securely // against the computed version. if _, err := file.Read(original); err != nil { return err } if !hmac.Equal(computed, original) { return fmt.Errorf("invalid file HMAC on decryption for file '%s'", fullpath) } // Go back to the beginning of the file (minus the IV) for // decryption. if _, err := file.Seek(ivSize, 0); err != nil { return fmt.Errorf("couldn't seek back to the beginning of file '%s': %s", fullpath, err) } // Reset the number of bytes so it only includes the encrypted // bytes. left = fileInfo.Size() - int64(ivSize+hmacSize) } // The input buffer, and a temporary buffer for holding decrypted // plaintext. temp := make([]byte, bufferSize) // Set up a framing message to use to send the data. m := &Message{ Type: MessageType_FILE_NEXT.Enum(), } // Now that the integrity of the data has been verified, if needed, send // the data (after decryption, if necessary) to the receiver. for { // Figure out how many bytes to read on this iteration. readSize := int64(bufferSize) final := false if left <= bufferSize { readSize = left final = true m.Type = MessageType_FILE_LAST.Enum() } // Read the (maybe encrypted) bytes from the file. n, err := file.Read(buf[:readSize]) if err != nil { return err } left = left - int64(n) if hasKeys { ctr.XORKeyStream(temp[:n], buf[:n]) m.Data = temp[:n] } else { m.Data = buf[:n] } // Send the decrypted data to the receiver. if _, err := ms.WriteMessage(m); err != nil { return err } if final { break } } return nil }
// DecryptOAEP decrypts ciphertext using RSA-OAEP. // If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks. func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { if err := checkPub(&priv.PublicKey); err != nil { return nil, err } k := (priv.N.BitLen() + 7) / 8 if len(ciphertext) > k || k < hash.Size()*2+2 { err = ErrDecryption return } c := new(big.Int).SetBytes(ciphertext) m, err := decrypt(random, priv, c) if err != nil { return } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() // Converting the plaintext number to bytes will strip any // leading zeros so we may have to left pad. We do this unconditionally // to avoid leaking timing information. (Although we still probably // leak the number of leading zeros. It's not clear that we can do // anything about this.) em := leftPad(m.Bytes(), k) firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) seed := em[1 : hash.Size()+1] db := em[hash.Size()+1:] mgf1XOR(seed, hash, db) mgf1XOR(db, hash, seed) lHash2 := db[0:hash.Size()] // We have to validate the plaintext in constant time in order to avoid // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 // v2.0. In J. Kilian, editor, Advances in Cryptology. lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) // The remainder of the plaintext must be zero or more 0x00, followed // by 0x01, followed by the message. // lookingForIndex: 1 iff we are still looking for the 0x01 // index: the offset of the first 0x01 byte // invalid: 1 iff we saw a non-zero byte before the 0x01. var lookingForIndex, index, invalid int lookingForIndex = 1 rest := db[hash.Size():] for i := 0; i < len(rest); i++ { equals0 := subtle.ConstantTimeByteEq(rest[i], 0) equals1 := subtle.ConstantTimeByteEq(rest[i], 1) index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index) lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex) invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid) } if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { err = ErrDecryption return } msg = rest[index+1:] return }
func (b *Buffer) PrependHash(h hash.Hash) *Buffer { b.SliceBack(h.Size()) h.Sum(b.Value[:0]) return b }
func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { // See [1], section 9.1.1 hLen := hash.Size() sLen := len(salt) emLen := (emBits + 7) / 8 // 1. If the length of M is greater than the input limitation for the // hash function (2^61 - 1 octets for SHA-1), output "message too // long" and stop. // // 2. Let mHash = Hash(M), an octet string of length hLen. if len(mHash) != hLen { return nil, errors.New("crypto/rsa: input must be hashed message") } // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. if emLen < hLen+sLen+2 { return nil, errors.New("crypto/rsa: encoding error") } em := make([]byte, emLen) db := em[:emLen-sLen-hLen-2+1+sLen] h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] // 4. Generate a random octet string salt of length sLen; if sLen = 0, // then salt is the empty string. // // 5. Let // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; // // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. // // 6. Let H = Hash(M'), an octet string of length hLen. var prefix [8]byte hash.Write(prefix[:]) hash.Write(mHash) hash.Write(salt) h = hash.Sum(h[:0]) hash.Reset() // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 // zero octets. The length of PS may be 0. // // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length // emLen - hLen - 1. db[emLen-sLen-hLen-2] = 0x01 copy(db[emLen-sLen-hLen-1:], salt) // 9. Let dbMask = MGF(H, emLen - hLen - 1). // // 10. Let maskedDB = DB \xor dbMask. mgf1XOR(db, hash, h) // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in // maskedDB to zero. db[0] &= (0xFF >> uint(8*emLen-emBits)) // 12. Let EM = maskedDB || H || 0xbc. em[emLen-1] = 0xBC // 13. Output EM. return em, nil }
func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { // 1. If the length of M is greater than the input limitation for the // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" // and stop. // // 2. Let mHash = Hash(M), an octet string of length hLen. hLen := hash.Size() if hLen != len(mHash) { return ErrVerification } // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. emLen := (emBits + 7) / 8 if emLen < hLen+sLen+2 { return ErrVerification } // 4. If the rightmost octet of EM does not have hexadecimal value // 0xbc, output "inconsistent" and stop. if em[len(em)-1] != 0xBC { return ErrVerification } // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and // let H be the next hLen octets. db := em[:emLen-hLen-1] h := em[emLen-hLen-1 : len(em)-1] // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in // maskedDB are not all equal to zero, output "inconsistent" and // stop. if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 { return ErrVerification } // 7. Let dbMask = MGF(H, emLen - hLen - 1). // // 8. Let DB = maskedDB \xor dbMask. mgf1XOR(db, hash, h) // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB // to zero. db[0] &= (0xFF >> uint(8*emLen-emBits)) if sLen == PSSSaltLengthAuto { FindSaltLength: for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { switch db[emLen-hLen-sLen-2] { case 1: break FindSaltLength case 0: continue default: return ErrVerification } } if sLen < 0 { return ErrVerification } } else { // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero // or if the octet at position emLen - hLen - sLen - 1 (the leftmost // position is "position 1") does not have hexadecimal value 0x01, // output "inconsistent" and stop. for _, e := range db[:emLen-hLen-sLen-2] { if e != 0x00 { return ErrVerification } } if db[emLen-hLen-sLen-2] != 0x01 { return ErrVerification } } // 11. Let salt be the last sLen octets of DB. salt := db[len(db)-sLen:] // 12. Let // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. // // 13. Let H' = Hash(M'), an octet string of length hLen. var prefix [8]byte hash.Write(prefix[:]) hash.Write(mHash) hash.Write(salt) h0 := hash.Sum(nil) // 14. If H = H', output "consistent." Otherwise, output "inconsistent." if !bytes.Equal(h0, h) { return ErrVerification } return nil }
func signPayload(payload string, hash hash.Hash) string { hash.Write([]byte(payload)) signature := make([]byte, b64.EncodedLen(hash.Size())) b64.Encode(signature, hash.Sum(nil)) return string(signature) }
func NewKey(h hash.Hash) ([]byte, error) { return Random(h.Size()) }