support migrating anope databases

This commit is contained in:
Shivaram Lingamneni
2020-10-12 15:06:17 -04:00
parent 4336f56204
commit 82be9a8423
10 changed files with 790 additions and 44 deletions
+3
View File
@@ -1056,6 +1056,8 @@ func (am *AccountManager) checkPassphrase(accountName, passphrase string) (accou
}
case -1:
err = am.checkLegacyPassphrase(migrations.CheckAthemePassphrase, accountName, account.Credentials.PassphraseHash, passphrase)
case -2:
err = am.checkLegacyPassphrase(migrations.CheckAnopePassphrase, accountName, account.Credentials.PassphraseHash, passphrase)
default:
err = errAccountInvalidCredentials
}
@@ -1899,6 +1901,7 @@ const (
CredentialsSHA3Bcrypt CredentialsVersion = 1
// negative numbers for migration
CredentialsAtheme = -1
CredentialsAnope = -2
)
// AccountCredentials stores the various methods for verifying accounts.
+2 -5
View File
@@ -358,11 +358,8 @@ func (reg *ChannelRegistry) saveChannel(tx *buntdb.Tx, channelInfo RegisteredCha
if includeFlags&IncludeModes != 0 {
tx.Set(fmt.Sprintf(keyChannelPassword, channelKey), channelInfo.Key, nil)
modeStrings := make([]string, len(channelInfo.Modes))
for i, mode := range channelInfo.Modes {
modeStrings[i] = string(mode)
}
tx.Set(fmt.Sprintf(keyChannelModes, channelKey), strings.Join(modeStrings, ""), nil)
modeString := modes.Modes(channelInfo.Modes).String()
tx.Set(fmt.Sprintf(keyChannelModes, channelKey), modeString, nil)
tx.Set(fmt.Sprintf(keyChannelUserLimit, channelKey), strconv.Itoa(channelInfo.UserLimit), nil)
}
+54 -18
View File
@@ -9,7 +9,6 @@ import (
"io/ioutil"
"log"
"strconv"
"strings"
"github.com/tidwall/buntdb"
@@ -17,13 +16,12 @@ import (
)
type userImport struct {
Name string
Hash string
Email string
RegisteredAt int64 `json:"registeredAt"`
Vhost string
AdditionalNicks []string `json:"additionalNicks"`
RegisteredChannels []string
Name string
Hash string
Email string
RegisteredAt int64 `json:"registeredAt"`
Vhost string
AdditionalNicks []string `json:"additionalNicks"`
}
type channelImport struct {
@@ -33,7 +31,10 @@ type channelImport struct {
Topic string
TopicSetBy string `json:"topicSetBy"`
TopicSetAt int64 `json:"topicSetAt"`
Amode map[string]int
Amode map[string]string
Modes string
Key string
Limit int
}
type databaseImport struct {
@@ -43,7 +44,23 @@ type databaseImport struct {
Channels map[string]channelImport
}
func doImportAthemeDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (err error) {
func serializeAmodes(raw map[string]string) (result []byte, err error) {
processed := make(map[string]int, len(raw))
for accountName, mode := range raw {
if len(mode) != 1 {
return nil, fmt.Errorf("invalid mode %s for account %s", mode, accountName)
}
cfname, err := CasefoldName(accountName)
if err != nil {
return nil, fmt.Errorf("invalid amode recipient %s: %w", accountName, err)
}
processed[cfname] = int(mode[0])
}
result, err = json.Marshal(processed)
return
}
func doImportDBGeneric(config *Config, dbImport databaseImport, credsType CredentialsVersion, tx *buntdb.Tx) (err error) {
requiredVersion := 1
if dbImport.Version != requiredVersion {
return fmt.Errorf("unsupported version of the db for import: version %d is required", requiredVersion)
@@ -63,7 +80,7 @@ func doImportAthemeDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (e
continue
}
credentials := AccountCredentials{
Version: CredentialsAtheme,
Version: credsType,
PassphraseHash: []byte(userInfo.Hash),
}
marshaledCredentials, err := json.Marshal(&credentials)
@@ -83,9 +100,6 @@ func doImportAthemeDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (e
if len(userInfo.AdditionalNicks) != 0 {
tx.Set(fmt.Sprintf(keyAccountAdditionalNicks, cfUsername), marshalReservedNicks(userInfo.AdditionalNicks), nil)
}
if len(userInfo.RegisteredChannels) != 0 {
tx.Set(fmt.Sprintf(keyAccountChannels, cfUsername), strings.Join(userInfo.RegisteredChannels, ","), nil)
}
}
for chname, chInfo := range dbImport.Channels {
@@ -94,23 +108,43 @@ func doImportAthemeDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (e
log.Printf("invalid channel name %s: %v", chname, err)
continue
}
cffounder, err := CasefoldName(chInfo.Founder)
if err != nil {
log.Printf("invalid founder %s for channel %s: %v", chInfo.Founder, chname, err)
continue
}
tx.Set(fmt.Sprintf(keyChannelExists, cfchname), "1", nil)
tx.Set(fmt.Sprintf(keyChannelName, cfchname), chname, nil)
tx.Set(fmt.Sprintf(keyChannelRegTime, cfchname), strconv.FormatInt(chInfo.RegisteredAt, 10), nil)
tx.Set(fmt.Sprintf(keyChannelFounder, cfchname), chInfo.Founder, nil)
tx.Set(fmt.Sprintf(keyChannelFounder, cfchname), cffounder, nil)
accountChannelsKey := fmt.Sprintf(keyAccountChannels, cffounder)
founderChannels, fcErr := tx.Get(accountChannelsKey)
if fcErr != nil || founderChannels == "" {
founderChannels = cfchname
} else {
founderChannels = fmt.Sprintf("%s,%s", founderChannels, cfchname)
}
tx.Set(accountChannelsKey, founderChannels, nil)
if chInfo.Topic != "" {
tx.Set(fmt.Sprintf(keyChannelTopic, cfchname), chInfo.Topic, nil)
tx.Set(fmt.Sprintf(keyChannelTopicSetTime, cfchname), strconv.FormatInt(chInfo.TopicSetAt, 10), nil)
tx.Set(fmt.Sprintf(keyChannelTopicSetBy, cfchname), chInfo.TopicSetBy, nil)
}
if len(chInfo.Amode) != 0 {
m, err := json.Marshal(chInfo.Amode)
m, err := serializeAmodes(chInfo.Amode)
if err == nil {
tx.Set(fmt.Sprintf(keyChannelAccountToUMode, cfchname), string(m), nil)
} else {
log.Printf("couldn't serialize amodes for %s: %v", chname, err)
}
}
tx.Set(fmt.Sprintf(keyChannelModes, cfchname), chInfo.Modes, nil)
if chInfo.Key != "" {
tx.Set(fmt.Sprintf(keyChannelPassword, cfchname), chInfo.Key, nil)
}
if chInfo.Limit > 0 {
tx.Set(fmt.Sprintf(keyChannelUserLimit, cfchname), strconv.Itoa(chInfo.Limit), nil)
}
}
return nil
@@ -119,9 +153,11 @@ func doImportAthemeDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (e
func doImportDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (err error) {
switch dbImport.Source {
case "atheme":
return doImportAthemeDB(config, dbImport, tx)
return doImportDBGeneric(config, dbImport, CredentialsAtheme, tx)
case "anope":
return doImportDBGeneric(config, dbImport, CredentialsAnope, tx)
default:
return fmt.Errorf("only imports from atheme are currently supported")
return fmt.Errorf("unsupported import source: %s", dbImport.Source)
}
}
+100 -2
View File
@@ -9,12 +9,14 @@ import (
"crypto/sha512"
"crypto/subtle"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"hash"
"strconv"
"github.com/GehirnInc/crypt/md5_crypt"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/pbkdf2"
)
@@ -24,15 +26,18 @@ var (
hmacServerKeyText = []byte("Server Key")
athemePBKDF2V2Prefix = []byte("$z")
athemeRawSHA1Prefix = []byte("$rawsha1$")
)
type PassphraseCheck func(hash, passphrase []byte) (err error)
func CheckAthemePassphrase(hash, passphrase []byte) (err error) {
if len(hash) < 60 {
return checkAthemePosixCrypt(hash, passphrase)
if bytes.HasPrefix(hash, athemeRawSHA1Prefix) {
return checkAthemeRawSha1(hash, passphrase)
} else if bytes.HasPrefix(hash, athemePBKDF2V2Prefix) {
return checkAthemePBKDF2V2(hash, passphrase)
} else if len(hash) < 60 {
return checkAthemePosixCrypt(hash, passphrase)
} else {
return checkAthemePBKDF2(hash, passphrase)
}
@@ -181,3 +186,96 @@ func checkAthemePBKDF2(hash, passphrase []byte) (err error) {
return ErrHashCheckFailed
}
}
func checkAthemeRawSha1(hash, passphrase []byte) (err error) {
return checkRawHash(hash[len(athemeRawSHA1Prefix):], passphrase, sha1.New())
}
func checkRawHash(expected, passphrase []byte, h hash.Hash) (err error) {
var rawExpected []byte
size := h.Size()
if len(expected) == 2*size {
rawExpected = make([]byte, h.Size())
_, err = hex.Decode(rawExpected, expected)
if err != nil {
return ErrHashInvalid
}
} else if len(expected) == size {
rawExpected = expected
} else {
return ErrHashInvalid
}
h.Write(passphrase)
hashedPassphrase := h.Sum(nil)
if subtle.ConstantTimeCompare(rawExpected, hashedPassphrase) == 1 {
return nil
} else {
return ErrHashCheckFailed
}
}
func checkAnopeEncSha256(hashBytes, ivBytes, passphrase []byte) (err error) {
if len(ivBytes) != 32 {
return ErrHashInvalid
}
// https://github.com/anope/anope/blob/2cf507ed662620d0b97c8484fbfbfa09265e86e1/modules/encryption/enc_sha256.cpp#L67
var iv [8]uint32
for i := 0; i < 8; i++ {
iv[i] = binary.BigEndian.Uint32(ivBytes[i*4 : (i+1)*4])
}
result := anopeSum256(passphrase, iv)
if subtle.ConstantTimeCompare(result[:], hashBytes) == 1 {
return nil
} else {
return ErrHashCheckFailed
}
}
func CheckAnopePassphrase(hash, passphrase []byte) (err error) {
pieces := bytes.Split(hash, []byte{':'})
if len(pieces) < 2 {
return ErrHashInvalid
}
switch string(pieces[0]) {
case "plain":
// base64, standard encoding
expectedPassphrase, err := base64.StdEncoding.DecodeString(string(pieces[1]))
if err != nil {
return ErrHashInvalid
}
if subtle.ConstantTimeCompare(passphrase, expectedPassphrase) == 1 {
return nil
} else {
return ErrHashCheckFailed
}
case "md5":
// raw MD5
return checkRawHash(pieces[1], passphrase, md5.New())
case "sha1":
// raw SHA-1
return checkRawHash(pieces[1], passphrase, sha1.New())
case "bcrypt":
if bcrypt.CompareHashAndPassword(pieces[1], passphrase) == nil {
return nil
} else {
return ErrHashCheckFailed
}
case "sha256":
// SHA-256 with an overridden IV
if len(pieces) != 3 {
return ErrHashInvalid
}
hashBytes, err := hex.DecodeString(string(pieces[1]))
if err != nil {
return ErrHashInvalid
}
ivBytes, err := hex.DecodeString(string(pieces[2]))
if err != nil {
return ErrHashInvalid
}
return checkAnopeEncSha256(hashBytes, ivBytes, passphrase)
default:
return ErrHashInvalid
}
}
+142
View File
@@ -11,6 +11,7 @@ import (
func TestAthemePassphrases(t *testing.T) {
var err error
// modules/crypto/crypt3-md5:
err = CheckAthemePassphrase([]byte("$1$hcspif$nCm4r3S14Me9ifsOPGuJT."), []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
@@ -21,6 +22,16 @@ func TestAthemePassphrases(t *testing.T) {
t.Errorf("accepted invalid passphrase")
}
err = CheckAthemePassphrase([]byte("$1$diwesm$9MjapdOyhyC.2FdHzKMzK."), []byte("1Ss1GN4q-3e8SgIJblfQxw"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAthemePassphrase([]byte("$1$hcspif$nCm4r3S14Me9ifsOPGuJT."), []byte("sh1varampassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
// modules/crypto/pbkdf2:
err = CheckAthemePassphrase([]byte("khMlbBBIFya2ihyN42abc3e768663e2c4fd0e0020e46292bf9fdf44e9a51d2a2e69509cb73b4b1bf9c1b6355a1fc9ea663fcd6da902287159494f15b905e5e651d6a60f2ec834598"), []byte("password"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
@@ -31,6 +42,7 @@ func TestAthemePassphrases(t *testing.T) {
t.Errorf("accepted invalid passphrase")
}
// modules/crypto/pbkdf2v2:
err = CheckAthemePassphrase([]byte("$z$65$64000$1kz1I9YJPJ2gkJALbrpL2DoxRDhYPBOg60KNJMK/6do=$Cnfg6pYhBNrVXiaXYH46byrC+3HKet/XvYwvI1BvZbs=$m0hrT33gcF90n2TU3lm8tdm9V9XC4xEV13KsjuT38iY="), []byte("password"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
@@ -40,6 +52,30 @@ func TestAthemePassphrases(t *testing.T) {
if err == nil {
t.Errorf("accepted invalid passphrase")
}
weirdHash := []byte("$z$6$64000$rWfIGzPY9qiIt7m5$VdFroDOlTQSLlFUJtpvlbp2i7sH3ZUndqwdnOvoDvt6b2AzLjaAK/lhSO/QaR2nA3Wm4ObHdl3WMW32NdtSMdw==")
err = CheckAthemePassphrase(weirdHash, []byte("pHQpwje5CjS3_Lx0RaeS7w"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAthemePassphrase(weirdHash, []byte("pHQpwje5CjS3-Lx0RaeS7w"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestAthemeRawSha1(t *testing.T) {
var err error
shivaramHash := []byte("$rawsha1$49fffa5543f21dd6effe88a79633e4073e36a828")
err = CheckAthemePassphrase(shivaramHash, []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAthemePassphrase(shivaramHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestOragonoLegacyPassphrase(t *testing.T) {
@@ -70,3 +106,109 @@ func TestOragonoLegacyPassphrase(t *testing.T) {
t.Errorf("accepted invalid passphrase")
}
}
func TestAnopePassphraseRawSha1(t *testing.T) {
var err error
shivaramHash := []byte("sha1:49fffa5543f21dd6effe88a79633e4073e36a828")
err = CheckAnopePassphrase(shivaramHash, []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(shivaramHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
edHash := []byte("sha1:ea44e256819de972c25fef0aa277396067d6024f")
err = CheckAnopePassphrase(edHash, []byte("edpassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(edHash, []byte("shivarampassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestAnopePassphraseRawMd5(t *testing.T) {
var err error
shivaramHash := []byte("md5:ce4bd864f37ffaa1b871aef22eea82ff")
err = CheckAnopePassphrase(shivaramHash, []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(shivaramHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
edHash := []byte("md5:dbf8be80e8dccdd33915b482e4390426")
err = CheckAnopePassphrase(edHash, []byte("edpassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(edHash, []byte("shivarampassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestAnopePassphrasePlain(t *testing.T) {
var err error
// not actually a hash
weirdHash := []byte("plain:YVxzMC1fMmZ+ZjM0OEAhN2FzZGYxNDJAIyFhZmE=")
err = CheckAnopePassphrase(weirdHash, []byte("a\\s0-_2f~f348@!7asdf142@#!afa"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(weirdHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestAnopePassphraseBcrypt(t *testing.T) {
var err error
shivaramHash := []byte("bcrypt:$2a$10$UyNgHyniPukGf/3A6vzBx.VMNfej0h4WzATg4ahKW2H86a0QLcVIK")
err = CheckAnopePassphrase(shivaramHash, []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(shivaramHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
func TestAnopePassphraseEncSha256(t *testing.T) {
var err error
shivaramHash := []byte("sha256:ff337943c8c4219cd330a3075a699492e0f8b1a823bb76af0129f1f117ba0630:60250c3053f7b34e35576fc5063b8b396fe7b9ab416842117991a8e027aa72f6")
err = CheckAnopePassphrase(shivaramHash, []byte("shivarampassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(shivaramHash, []byte("edpassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
edHash := []byte("sha256:93a430c8c3c6917dc6e9a32ac1aba90bc5768265278a45b86eacd636fc723d8f:10ea72683a499c155d72cd3571cb80e5050280620f789a44492c0e0c7956942f")
err = CheckAnopePassphrase(edHash, []byte("edpassphrase"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(edHash, []byte("shivarampassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
weirdHash := []byte("sha256:06d11a06025354e37a7ddf48913a1c9831ffab47d04e4c22a89fd7835abcb6cc:3137788c2749da0419bc9df320991d2d72495c7065da4f39004fd21710601409")
err = CheckAnopePassphrase(weirdHash, []byte("1Ss1GN4q-3e8SgIJblfQxw"))
if err != nil {
t.Errorf("failed to check passphrase: %v", err)
}
err = CheckAnopePassphrase(weirdHash, []byte("shivarampassphrase"))
if err == nil {
t.Errorf("accepted invalid passphrase")
}
}
+128
View File
@@ -0,0 +1,128 @@
/*
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// SHA256 implementation from golang/go, modified to accommodate anope's
// password hashing scheme, which overrides the initialization vector
// using the salt.
package migrations
import (
"encoding/binary"
)
// The size of a SHA256 checksum in bytes.
const Size = 32
const (
chunk = 64
)
// digest represents the partial evaluation of a checksum.
type digest struct {
h [8]uint32
x [chunk]byte
nx int
len uint64
}
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
sha256BlockGeneric(d, d.x[:])
d.nx = 0
}
p = p[n:]
}
if len(p) >= chunk {
n := len(p) &^ (chunk - 1)
sha256BlockGeneric(d, p[:n])
p = p[n:]
}
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d *digest) Sum(in []byte) []byte {
// Make a copy of d so that caller can keep writing and summing.
d0 := *d
hash := d0.checkSum()
return append(in, hash[:]...)
}
func (d *digest) checkSum() [Size]byte {
len := d.len
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
d.Write(tmp[0 : 56-len%64])
} else {
d.Write(tmp[0 : 64+56-len%64])
}
// Length in bits.
len <<= 3
binary.BigEndian.PutUint64(tmp[:], len)
d.Write(tmp[0:8])
if d.nx != 0 {
panic("d.nx != 0")
}
var digest [Size]byte
binary.BigEndian.PutUint32(digest[0:], d.h[0])
binary.BigEndian.PutUint32(digest[4:], d.h[1])
binary.BigEndian.PutUint32(digest[8:], d.h[2])
binary.BigEndian.PutUint32(digest[12:], d.h[3])
binary.BigEndian.PutUint32(digest[16:], d.h[4])
binary.BigEndian.PutUint32(digest[20:], d.h[5])
binary.BigEndian.PutUint32(digest[24:], d.h[6])
binary.BigEndian.PutUint32(digest[28:], d.h[7])
return digest
}
// Anope password hashing function: SHA-256 with an override for the IV
// The actual SHA-256 IV for reference:
// [8]uint32{0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19}
func anopeSum256(data []byte, iv [8]uint32) [Size]byte {
var d digest
d.h = iv
d.Write(data)
return d.checkSum()
}
+154
View File
@@ -0,0 +1,154 @@
/*
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// SHA256 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package migrations
import "math/bits"
var _K = []uint32{
0x428a2f98,
0x71374491,
0xb5c0fbcf,
0xe9b5dba5,
0x3956c25b,
0x59f111f1,
0x923f82a4,
0xab1c5ed5,
0xd807aa98,
0x12835b01,
0x243185be,
0x550c7dc3,
0x72be5d74,
0x80deb1fe,
0x9bdc06a7,
0xc19bf174,
0xe49b69c1,
0xefbe4786,
0x0fc19dc6,
0x240ca1cc,
0x2de92c6f,
0x4a7484aa,
0x5cb0a9dc,
0x76f988da,
0x983e5152,
0xa831c66d,
0xb00327c8,
0xbf597fc7,
0xc6e00bf3,
0xd5a79147,
0x06ca6351,
0x14292967,
0x27b70a85,
0x2e1b2138,
0x4d2c6dfc,
0x53380d13,
0x650a7354,
0x766a0abb,
0x81c2c92e,
0x92722c85,
0xa2bfe8a1,
0xa81a664b,
0xc24b8b70,
0xc76c51a3,
0xd192e819,
0xd6990624,
0xf40e3585,
0x106aa070,
0x19a4c116,
0x1e376c08,
0x2748774c,
0x34b0bcb5,
0x391c0cb3,
0x4ed8aa4a,
0x5b9cca4f,
0x682e6ff3,
0x748f82ee,
0x78a5636f,
0x84c87814,
0x8cc70208,
0x90befffa,
0xa4506ceb,
0xbef9a3f7,
0xc67178f2,
}
func sha256BlockGeneric(dig *digest, p []byte) {
var w [64]uint32
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
for len(p) >= chunk {
// Can interlace the computation of w with the
// rounds below if needed for speed.
for i := 0; i < 16; i++ {
j := i * 4
w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
}
for i := 16; i < 64; i++ {
v1 := w[i-2]
t1 := (bits.RotateLeft32(v1, -17)) ^ (bits.RotateLeft32(v1, -19)) ^ (v1 >> 10)
v2 := w[i-15]
t2 := (bits.RotateLeft32(v2, -7)) ^ (bits.RotateLeft32(v2, -18)) ^ (v2 >> 3)
w[i] = t1 + w[i-7] + t2 + w[i-16]
}
a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
for i := 0; i < 64; i++ {
t1 := h + ((bits.RotateLeft32(e, -6)) ^ (bits.RotateLeft32(e, -11)) ^ (bits.RotateLeft32(e, -25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
t2 := ((bits.RotateLeft32(a, -2)) ^ (bits.RotateLeft32(a, -13)) ^ (bits.RotateLeft32(a, -22))) + ((a & b) ^ (a & c) ^ (b & c))
h = g
g = f
f = e
e = d + t1
d = c
c = b
b = a
a = t1 + t2
}
h0 += a
h1 += b
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
p = p[chunk:]
}
dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
}
+4 -4
View File
@@ -89,11 +89,11 @@ func (changes ModeChanges) Strings() (result []string) {
type Modes []Mode
func (modes Modes) String() string {
strs := make([]string, len(modes))
for index, mode := range modes {
strs[index] = mode.String()
var builder strings.Builder
for _, m := range modes {
builder.WriteRune(rune(m))
}
return strings.Join(strs, "")
return builder.String()
}
// User Modes