mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Hash functions.
This commit is contained in:
30
ext/hash/blake2.go
Normal file
30
ext/hash/blake2.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
)
|
||||
|
||||
func blake2sFunc(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.BLAKE2s_256)
|
||||
}
|
||||
|
||||
func blake2bFunc(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
size := 512
|
||||
if len(arg) > 1 {
|
||||
size = arg[1].Int()
|
||||
}
|
||||
|
||||
switch size {
|
||||
case 256:
|
||||
hashFunc(ctx, arg[0], crypto.BLAKE2b_256)
|
||||
case 384:
|
||||
hashFunc(ctx, arg[0], crypto.BLAKE2b_384)
|
||||
case 512:
|
||||
hashFunc(ctx, arg[0], crypto.BLAKE2b_512)
|
||||
default:
|
||||
ctx.ResultError(util.ErrorString("blake2b: size must be 256, 384, 512"))
|
||||
}
|
||||
}
|
||||
98
ext/hash/hash.go
Normal file
98
ext/hash/hash.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Package hash provides cryptographic hash functions.
|
||||
//
|
||||
// Functions:
|
||||
// - md4(data)
|
||||
// - md5(data)
|
||||
// - sha1(data)
|
||||
// - sha3(data, size) (default size 256)
|
||||
// - sha224(data)
|
||||
// - sha256(data, size) (default size 256)
|
||||
// - sha384(data)
|
||||
// - sha512(data, size) (default size 512)
|
||||
// - blake2s(data)
|
||||
// - blake2b(data, size) (default size 512)
|
||||
// - ripemd160(data)
|
||||
//
|
||||
// Each SQL function will only be registered if the corresponding
|
||||
// [crypto.Hash] function is available.
|
||||
// To ensure a specific hash function is available,
|
||||
// import the implementing package.
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
)
|
||||
|
||||
// Register registers cryptographic hash functions for a database connection.
|
||||
func Register(db *sqlite3.Conn) {
|
||||
flags := sqlite3.DETERMINISTIC | sqlite3.INNOCUOUS
|
||||
|
||||
if crypto.MD4.Available() {
|
||||
db.CreateFunction("md4", 1, flags, md4Func)
|
||||
}
|
||||
if crypto.MD5.Available() {
|
||||
db.CreateFunction("md5", 1, flags, md5Func)
|
||||
}
|
||||
if crypto.SHA1.Available() {
|
||||
db.CreateFunction("sha1", 1, flags, sha1Func)
|
||||
}
|
||||
if crypto.SHA3_512.Available() {
|
||||
db.CreateFunction("sha3", 1, flags, sha3Func)
|
||||
db.CreateFunction("sha3", 2, flags, sha3Func)
|
||||
}
|
||||
if crypto.SHA256.Available() {
|
||||
db.CreateFunction("sha224", 1, flags, sha224Func)
|
||||
db.CreateFunction("sha256", 1, flags, sha256Func)
|
||||
db.CreateFunction("sha256", 2, flags, sha256Func)
|
||||
}
|
||||
if crypto.SHA512.Available() {
|
||||
db.CreateFunction("sha384", 1, flags, sha384Func)
|
||||
db.CreateFunction("sha512", 1, flags, sha512Func)
|
||||
db.CreateFunction("sha512", 2, flags, sha512Func)
|
||||
}
|
||||
if crypto.BLAKE2s_256.Available() {
|
||||
db.CreateFunction("blake2s", 1, flags, blake2sFunc)
|
||||
}
|
||||
if crypto.BLAKE2b_512.Available() {
|
||||
db.CreateFunction("blake2b", 1, flags, blake2bFunc)
|
||||
db.CreateFunction("blake2b", 2, flags, blake2bFunc)
|
||||
}
|
||||
if crypto.RIPEMD160.Available() {
|
||||
db.CreateFunction("ripemd160", 1, flags, ripemd160Func)
|
||||
}
|
||||
}
|
||||
|
||||
func md4Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.MD4)
|
||||
}
|
||||
|
||||
func md5Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.MD5)
|
||||
}
|
||||
|
||||
func sha1Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.SHA1)
|
||||
}
|
||||
|
||||
func ripemd160Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.RIPEMD160)
|
||||
}
|
||||
|
||||
func hashFunc(ctx sqlite3.Context, arg sqlite3.Value, fn crypto.Hash) {
|
||||
var data []byte
|
||||
switch arg.Type() {
|
||||
case sqlite3.NULL:
|
||||
return
|
||||
case sqlite3.BLOB:
|
||||
data = arg.RawBlob()
|
||||
default:
|
||||
data = arg.RawText()
|
||||
}
|
||||
|
||||
h := fn.New()
|
||||
h.Write(data)
|
||||
var res [64]byte
|
||||
ctx.ResultBlob(h.Sum(res[:0]))
|
||||
}
|
||||
98
ext/hash/hash_test.go
Normal file
98
ext/hash/hash_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
_ "crypto/md5"
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"testing"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/driver"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
_ "golang.org/x/crypto/blake2b"
|
||||
_ "golang.org/x/crypto/blake2s"
|
||||
_ "golang.org/x/crypto/md4"
|
||||
_ "golang.org/x/crypto/ripemd160"
|
||||
_ "golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
hash string
|
||||
}{
|
||||
{"md4(NULL)", ""},
|
||||
{"md4(X'')", "31D6CFE0D16AE931B73C59D7E0C089C0"},
|
||||
{"md4('The quick brown fox jumps over the lazy dog')", "1BEE69A46BA811185C194762ABAEAE90"},
|
||||
|
||||
{"md5('')", "D41D8CD98F00B204E9800998ECF8427E"},
|
||||
{"sha1('')", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"},
|
||||
{"ripemd160('')", "9C1185A5C5E9FC54612808977EE8F548B2258D31"},
|
||||
|
||||
{"sha224('')", "D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F"},
|
||||
{"sha256('')", "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"},
|
||||
{"sha256('', 224)", "D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F"},
|
||||
{"sha384('')", "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B"},
|
||||
{"sha512('')", "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"},
|
||||
{"sha512('', 224)", "6ED0DD02806FA89E25DE060C19D3AC86CABB87D6A0DDD05C333B84F4"},
|
||||
{"sha512('', 256)", "C672B8D1EF56ED28AB87C3622C5114069BDD3AD7B8F9737498D0C01ECEF0967A"},
|
||||
{"sha512('', 384)", "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B"},
|
||||
|
||||
{"sha3('')", "A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A"},
|
||||
{"sha3('', 224)", "6B4E03423667DBB73B6E15454F0EB1ABD4597F9A1B078E3F5B5A6BC7"},
|
||||
{"sha3('', 384)", "0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2AC3713831264ADB47FB6BD1E058D5F004"},
|
||||
{"sha3('', 512)", "A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26"},
|
||||
|
||||
{"blake2s('')", "69217A3079908094E11121D042354A7C1F55B6482CA1A51E1B250DFD1ED0EEF9"},
|
||||
{"blake2b('')", "786A02F742015903C6C6FD852552D272912F4740E15847618A86E217F71F5419D25E1031AFEE585313896444934EB04B903A685B1448B755D56F701AFE9BE2CE"},
|
||||
{"blake2b('', 384)", "B32811423377F52D7862286EE1A72EE540524380FDA1724A6F25D7978C6FD3244A6CAF0498812673C5E05EF583825100"},
|
||||
{"blake2b('', 256)", "0E5751C026E543B2E8AB2EB06099DAA1D1E5DF47778F7787FAAB45CDF12FE3A8"},
|
||||
}
|
||||
|
||||
db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error {
|
||||
Register(c)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var hash string
|
||||
|
||||
err = db.QueryRow(`SELECT hex(` + tt.name + `)`).Scan(&hash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hash != tt.hash {
|
||||
t.Errorf("got %s, want %s", hash, tt.hash)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_, err = db.Exec(`SELECT sha256('', 255)`)
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
|
||||
_, err = db.Exec(`SELECT sha512('', 255)`)
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
|
||||
_, err = db.Exec(`SELECT sha3('', 255)`)
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
|
||||
_, err = db.Exec(`SELECT blake2b('', 255)`)
|
||||
if err == nil {
|
||||
t.Error("want error")
|
||||
}
|
||||
}
|
||||
53
ext/hash/sha2.go
Normal file
53
ext/hash/sha2.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
)
|
||||
|
||||
func sha224Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.SHA224)
|
||||
}
|
||||
|
||||
func sha384Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
hashFunc(ctx, arg[0], crypto.SHA384)
|
||||
}
|
||||
|
||||
func sha256Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
size := 256
|
||||
if len(arg) > 1 {
|
||||
size = arg[1].Int()
|
||||
}
|
||||
|
||||
switch size {
|
||||
case 224:
|
||||
hashFunc(ctx, arg[0], crypto.SHA224)
|
||||
case 256:
|
||||
hashFunc(ctx, arg[0], crypto.SHA256)
|
||||
default:
|
||||
ctx.ResultError(util.ErrorString("sha256: size must be 224, 256"))
|
||||
}
|
||||
}
|
||||
|
||||
func sha512Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
size := 512
|
||||
if len(arg) > 1 {
|
||||
size = arg[1].Int()
|
||||
}
|
||||
|
||||
switch size {
|
||||
case 224:
|
||||
hashFunc(ctx, arg[0], crypto.SHA512_224)
|
||||
case 256:
|
||||
hashFunc(ctx, arg[0], crypto.SHA512_256)
|
||||
case 384:
|
||||
hashFunc(ctx, arg[0], crypto.SHA384)
|
||||
case 512:
|
||||
hashFunc(ctx, arg[0], crypto.SHA512)
|
||||
default:
|
||||
ctx.ResultError(util.ErrorString("sha512: size must be 224, 256, 384, 512"))
|
||||
}
|
||||
|
||||
}
|
||||
28
ext/hash/sha3.go
Normal file
28
ext/hash/sha3.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
)
|
||||
|
||||
func sha3Func(ctx sqlite3.Context, arg ...sqlite3.Value) {
|
||||
size := 256
|
||||
if len(arg) > 1 {
|
||||
size = arg[1].Int()
|
||||
}
|
||||
|
||||
switch size {
|
||||
case 224:
|
||||
hashFunc(ctx, arg[0], crypto.SHA3_224)
|
||||
case 256:
|
||||
hashFunc(ctx, arg[0], crypto.SHA3_256)
|
||||
case 384:
|
||||
hashFunc(ctx, arg[0], crypto.SHA3_384)
|
||||
case 512:
|
||||
hashFunc(ctx, arg[0], crypto.SHA3_512)
|
||||
default:
|
||||
ctx.ResultError(util.ErrorString("sha3: size must be 224, 256, 384, 512"))
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
sha3
|
||||
sha3_query
|
||||
|
||||
ieee754
|
||||
ieee754_exponent
|
||||
ieee754_from_blob
|
||||
|
||||
1
go.mod
1
go.mod
@@ -6,6 +6,7 @@ require (
|
||||
github.com/ncruces/julianday v1.0.0
|
||||
github.com/psanford/httpreadat v0.1.0
|
||||
github.com/tetratelabs/wazero v1.6.0
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/text v0.14.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -4,6 +4,8 @@ github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIw
|
||||
github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE=
|
||||
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
|
||||
Reference in New Issue
Block a user