├── .github
└── workflows
│ └── ci.yml
├── LICENSE
├── MAINTENANCE
├── Makefile
├── README.md
├── _example
├── custom_func
│ └── main.go
├── hook
│ └── hook.go
├── limit
│ └── limit.go
├── mod_regexp
│ ├── Makefile
│ ├── extension.go
│ └── sqlite3_mod_regexp.c
├── mod_vtable
│ ├── Makefile
│ ├── extension.go
│ ├── picojson.h
│ └── sqlite3_mod_vtable.cc
├── simple
│ └── simple.go
├── trace
│ └── main.go
└── vtable
│ ├── main.go
│ └── vtable.go
├── aes.c
├── aes_tab.h
├── backup.go
├── backup_test.go
├── burn_stack.c
├── callback.go
├── callback_test.go
├── cbc_decrypt.c
├── cbc_done.c
├── cbc_encrypt.c
├── cbc_start.c
├── compare_testvector.c
├── convert.go
├── crypt_argchk.c
├── crypt_cipher_descriptor.c
├── crypt_cipher_is_valid.c
├── crypt_find_cipher.c
├── crypt_find_hash.c
├── crypt_hash_descriptor.c
├── crypt_hash_is_valid.c
├── crypt_prng_descriptor.c
├── crypt_register_cipher.c
├── crypt_register_hash.c
├── crypt_register_prng.c
├── doc.go
├── error.go
├── error_test.go
├── flags.go
├── fortuna.c
├── go.mod
├── go.sum
├── hash_memory.c
├── hmac_done.c
├── hmac_init.c
├── hmac_memory.c
├── hmac_process.c
├── pkcs_5_2.c
├── sha1.c
├── sha256.c
├── sha512.c
├── sqlcipher.go
├── sqlcipher_test.go
├── sqlite3.c
├── sqlite3.go
├── sqlite3.h
├── sqlite3_context.go
├── sqlite3_func_crypt.go
├── sqlite3_func_crypt_test.go
├── sqlite3_go113_test.go
├── sqlite3_go18.go
├── sqlite3_go18_test.go
├── sqlite3_libsqlite3.go
├── sqlite3_load_extension.go
├── sqlite3_load_extension_omit.go
├── sqlite3_load_extension_test.go
├── sqlite3_opt_allow_uri_authority.go
├── sqlite3_opt_app_armor.go
├── sqlite3_opt_foreign_keys.go
├── sqlite3_opt_fts3_test.go
├── sqlite3_opt_fts5.go
├── sqlite3_opt_icu.go
├── sqlite3_opt_introspect.go
├── sqlite3_opt_json1.go
├── sqlite3_opt_preupdate.go
├── sqlite3_opt_preupdate_hook.go
├── sqlite3_opt_preupdate_hook_test.go
├── sqlite3_opt_preupdate_omit.go
├── sqlite3_opt_secure_delete.go
├── sqlite3_opt_secure_delete_fast.go
├── sqlite3_opt_stat4.go
├── sqlite3_opt_unlock_notify.c
├── sqlite3_opt_unlock_notify.go
├── sqlite3_opt_unlock_notify_test.go
├── sqlite3_opt_userauth.go
├── sqlite3_opt_userauth_omit.go
├── sqlite3_opt_userauth_test.go
├── sqlite3_opt_vacuum_full.go
├── sqlite3_opt_vacuum_incr.go
├── sqlite3_opt_vtable.go
├── sqlite3_opt_vtable_test.go
├── sqlite3_other.go
├── sqlite3_solaris.go
├── sqlite3_test.go
├── sqlite3_trace.go
├── sqlite3_type.go
├── sqlite3_usleep_windows.go
├── sqlite3_windows.go
├── static_mock.go
├── testdata
├── sqlcipher3.sqlite3
└── sqlcipher4.sqlite3
├── tomcrypt.h
├── tomcrypt_argchk.h
├── tomcrypt_cfg.h
├── tomcrypt_cipher.h
├── tomcrypt_custom.h
├── tomcrypt_hash.h
├── tomcrypt_mac.h
├── tomcrypt_macros.h
├── tomcrypt_math.h
├── tomcrypt_misc.h
├── tomcrypt_pk.h
├── tomcrypt_pkcs.h
├── tomcrypt_private.h
├── tomcrypt_prng.h
├── track_go-sqlite3.sh
├── track_libtomcrypt.sh
├── upgrade
├── package.go
└── upgrade.go
├── util
├── create
│ └── create.go
└── select
│ └── select.go
└── zeromem.c
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | strategy:
8 | matrix:
9 | go-version: [1.13.x, 1.14.x, 1.15.x]
10 | platform: [ubuntu-latest]
11 | runs-on: ${{ matrix.platform }}
12 | steps:
13 | - name: Install Go
14 | uses: actions/setup-go@v2
15 | with:
16 | go-version: ${{ matrix.go-version }}
17 | - name: Checkout code
18 | uses: actions/checkout@v2
19 | - name: Test
20 | run: |
21 | go get github.com/frankbraun/gocheck
22 | export PATH=$GOPATH/bin:$PATH
23 | make test
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The code taken from https://github.com/mattn/go-sqlite3 is licensed under:
2 |
3 | The MIT License (MIT)
4 |
5 | Copyright (c) 2014 Yasuhiro Matsumoto
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
25 | --------------------------------------------------------------------------------
26 |
27 | The code taken from https://github.com/sqlcipher/sqlcipher is licensed under:
28 |
29 | Copyright (c) 2008, ZETETIC LLC
30 | All rights reserved.
31 |
32 | Redistribution and use in source and binary forms, with or without
33 | modification, are permitted provided that the following conditions are met:
34 | * Redistributions of source code must retain the above copyright
35 | notice, this list of conditions and the following disclaimer.
36 | * Redistributions in binary form must reproduce the above copyright
37 | notice, this list of conditions and the following disclaimer in the
38 | documentation and/or other materials provided with the distribution.
39 | * Neither the name of the ZETETIC LLC nor the
40 | names of its contributors may be used to endorse or promote products
41 | derived from this software without specific prior written permission.
42 |
43 | THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
44 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46 | DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
47 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
50 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
52 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 |
54 | --------------------------------------------------------------------------------
55 |
56 | SQLite itself is unlicensed with the following notice:
57 |
58 | The author disclaims copyright to this source code. In place of
59 | a legal notice, here is a blessing:
60 |
61 | May you do good and not evil.
62 | May you find forgiveness for yourself and forgive others.
63 | May you share freely, never taking more than you give.
64 |
65 | --------------------------------------------------------------------------------
66 |
67 | The code taken from https://github.com/libtom/libtomcrypt is unlicensed with the
68 | following notice:
69 |
70 | The LibTom license
71 |
72 | This is free and unencumbered software released into the public domain.
73 |
74 | Anyone is free to copy, modify, publish, use, compile, sell, or
75 | distribute this software, either in source code form or as a compiled
76 | binary, for any purpose, commercial or non-commercial, and by any
77 | means.
78 |
79 | In jurisdictions that recognize copyright laws, the author or authors
80 | of this software dedicate any and all copyright interest in the
81 | software to the public domain. We make this dedication for the benefit
82 | of the public at large and to the detriment of our heirs and
83 | successors. We intend this dedication to be an overt act of
84 | relinquishment in perpetuity of all present and future rights to this
85 | software under copyright law.
86 |
87 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
88 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
89 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
90 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
91 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
92 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
93 | OTHER DEALINGS IN THE SOFTWARE.
94 |
95 | For more information, please refer to
96 |
--------------------------------------------------------------------------------
/MAINTENANCE:
--------------------------------------------------------------------------------
1 | To maintain this code properly, the following three repositories have to be
2 | tracked for changes (maintenance details below):
3 |
4 | - https://github.com/mattn/go-sqlite
5 | - https://github.com/sqlcipher/sqlcipher
6 | - https://github.com/libtom/libtomcrypt
7 |
8 |
9 | Update code from https://github.com/mattn/go-sqlite3
10 | ----------------------------------------------------
11 |
12 | Current release: v1.14.5
13 |
14 | Use ./track_go-sqlite3.sh
15 |
16 |
17 | Update code from https://github.com/sqlcipher/sqlcipher
18 | -------------------------------------------------------
19 |
20 | Current release: v4.4.2
21 |
22 | Execute:
23 | ./configure
24 | make
25 |
26 | Track files:
27 | sqlite3.h
28 | sqlite3.c
29 |
30 |
31 | Update code from https://github.com/libtom/libtomcrypt
32 | ------------------------------------------------------
33 |
34 | Current HEAD: cfbd7f8d364e1438555ff2a247f7e17add11840e
35 | (from develop branch, 2020-08-29)
36 |
37 | Use ./track_libtomcrypt.sh
38 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all test update-modules
2 |
3 | all:
4 | env GO111MODULE=on go build -v ./...
5 |
6 | test:
7 | gocheck -g -c -e _example -e sqlite3_test -novet
8 |
9 | update-modules:
10 | env GO111MODULE=on go get -u
11 | env GO111MODULE=on go mod tidy -v
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## go-sqlcipher
2 |
3 | [](http://godoc.org/github.com/mutecomm/go-sqlcipher) [](https://github.com/mutecomm/go-sqlcipher/actions)
4 |
5 | ### Description
6 |
7 | Self-contained Go sqlite3 driver with an AES-256 encrypted sqlite3 database
8 | conforming to the built-in database/sql interface. It is based on:
9 |
10 | - Go sqlite3 driver: https://github.com/mattn/go-sqlite3
11 | - SQLite extension with AES-256 codec: https://github.com/sqlcipher/sqlcipher
12 | - AES-256 implementation from: https://github.com/libtom/libtomcrypt
13 |
14 | SQLite itself is part of SQLCipher.
15 |
16 | ### Incompatibilities of SQLCipher
17 |
18 | The version tags of go-sqlcipher are the same as for SQLCipher.
19 |
20 | **SQLCipher 4.x is incompatible with SQLCipher 3.x!**
21 |
22 | go-sqlcipher does not implement any migration strategies at the moment.
23 | So if you upgrade a major version of go-sqlcipher, you yourself are responsible
24 | to upgrade existing database files.
25 |
26 | See [migrating databases](https://www.zetetic.net/sqlcipher/sqlcipher-api/#Migrating_Databases) for details.
27 |
28 | To upgrade your Go code to the 4.x series, change the import path to
29 |
30 | "github.com/mutecomm/go-sqlcipher/v4"
31 |
32 | ### Installation
33 |
34 | This package can be installed with the go get command:
35 |
36 | go get github.com/mutecomm/go-sqlcipher
37 |
38 |
39 | ### Documentation
40 |
41 | To create and open encrypted database files use the following DSN parameters:
42 |
43 | ```go
44 | key := "2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99"
45 | dbname := fmt.Sprintf("db?_pragma_key=x'%s'&_pragma_cipher_page_size=4096", key)
46 | db, _ := sql.Open("sqlite3", dbname)
47 | ```
48 |
49 | `_pragma_key` is the hex encoded 32 byte key (must be 64 characters long).
50 | `_pragma_cipher_page_size` is the page size of the encrypted database (set if
51 | you want a different value than the default size).
52 |
53 | ```go
54 | key := url.QueryEscape("secret")
55 | dbname := fmt.Sprintf("db?_pragma_key=%s&_pragma_cipher_page_size=4096", key)
56 | db, _ := sql.Open("sqlite3", dbname)
57 | ```
58 |
59 | This uses a passphrase directly as `_pragma_key` with the key derivation function in
60 | SQLCipher. Do not forget the `url.QueryEscape()` call in your code!
61 |
62 | See also [PRAGMA key](https://www.zetetic.net/sqlcipher/sqlcipher-api/#PRAGMA_key).
63 |
64 | API documentation can be found here:
65 | http://godoc.org/github.com/mutecomm/go-sqlcipher
66 |
67 | Use the function
68 | [sqlite3.IsEncrypted()](https://godoc.org/github.com/mutecomm/go-sqlcipher#IsEncrypted)
69 | to check whether a database file is encrypted or not.
70 |
71 | Examples can be found under the `./_example` directory
72 |
73 |
74 | ### License
75 |
76 | The code of the originating packages is covered by their respective licenses.
77 | See [LICENSE](LICENSE) file for details.
78 |
--------------------------------------------------------------------------------
/_example/custom_func/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "math"
8 | "math/rand"
9 |
10 | sqlite "github.com/mutecomm/go-sqlcipher/v4"
11 | )
12 |
13 | // Computes x^y
14 | func pow(x, y int64) int64 {
15 | return int64(math.Pow(float64(x), float64(y)))
16 | }
17 |
18 | // Computes the bitwise exclusive-or of all its arguments
19 | func xor(xs ...int64) int64 {
20 | var ret int64
21 | for _, x := range xs {
22 | ret ^= x
23 | }
24 | return ret
25 | }
26 |
27 | // Returns a random number. It's actually deterministic here because
28 | // we don't seed the RNG, but it's an example of a non-pure function
29 | // from SQLite's POV.
30 | func getrand() int64 {
31 | return rand.Int63()
32 | }
33 |
34 | // Computes the standard deviation of a GROUPed BY set of values
35 | type stddev struct {
36 | xs []int64
37 | // Running average calculation
38 | sum int64
39 | n int64
40 | }
41 |
42 | func newStddev() *stddev { return &stddev{} }
43 |
44 | func (s *stddev) Step(x int64) {
45 | s.xs = append(s.xs, x)
46 | s.sum += x
47 | s.n++
48 | }
49 |
50 | func (s *stddev) Done() float64 {
51 | mean := float64(s.sum) / float64(s.n)
52 | var sqDiff []float64
53 | for _, x := range s.xs {
54 | sqDiff = append(sqDiff, math.Pow(float64(x)-mean, 2))
55 | }
56 | var dev float64
57 | for _, x := range sqDiff {
58 | dev += x
59 | }
60 | dev /= float64(len(sqDiff))
61 | return math.Sqrt(dev)
62 | }
63 |
64 | func main() {
65 | sql.Register("sqlite3_custom", &sqlite.SQLiteDriver{
66 | ConnectHook: func(conn *sqlite.SQLiteConn) error {
67 | if err := conn.RegisterFunc("pow", pow, true); err != nil {
68 | return err
69 | }
70 | if err := conn.RegisterFunc("xor", xor, true); err != nil {
71 | return err
72 | }
73 | if err := conn.RegisterFunc("rand", getrand, false); err != nil {
74 | return err
75 | }
76 | if err := conn.RegisterAggregator("stddev", newStddev, true); err != nil {
77 | return err
78 | }
79 | return nil
80 | },
81 | })
82 |
83 | db, err := sql.Open("sqlite3_custom", ":memory:")
84 | if err != nil {
85 | log.Fatal("Failed to open database:", err)
86 | }
87 | defer db.Close()
88 |
89 | var i int64
90 | err = db.QueryRow("SELECT pow(2,3)").Scan(&i)
91 | if err != nil {
92 | log.Fatal("POW query error:", err)
93 | }
94 | fmt.Println("pow(2,3) =", i) // 8
95 |
96 | err = db.QueryRow("SELECT xor(1,2,3,4,5,6)").Scan(&i)
97 | if err != nil {
98 | log.Fatal("XOR query error:", err)
99 | }
100 | fmt.Println("xor(1,2,3,4,5) =", i) // 7
101 |
102 | err = db.QueryRow("SELECT rand()").Scan(&i)
103 | if err != nil {
104 | log.Fatal("RAND query error:", err)
105 | }
106 | fmt.Println("rand() =", i) // pseudorandom
107 |
108 | _, err = db.Exec("create table foo (department integer, profits integer)")
109 | if err != nil {
110 | log.Fatal("Failed to create table:", err)
111 | }
112 | _, err = db.Exec("insert into foo values (1, 10), (1, 20), (1, 45), (2, 42), (2, 115)")
113 | if err != nil {
114 | log.Fatal("Failed to insert records:", err)
115 | }
116 |
117 | rows, err := db.Query("select department, stddev(profits) from foo group by department")
118 | if err != nil {
119 | log.Fatal("STDDEV query error:", err)
120 | }
121 | defer rows.Close()
122 | for rows.Next() {
123 | var dept int64
124 | var dev float64
125 | if err := rows.Scan(&dept, &dev); err != nil {
126 | log.Fatal(err)
127 | }
128 | fmt.Printf("dept=%d stddev=%f\n", dept, dev)
129 | }
130 | if err := rows.Err(); err != nil {
131 | log.Fatal(err)
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/_example/hook/hook.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "log"
6 | "os"
7 |
8 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
9 | )
10 |
11 | func main() {
12 | sqlite3conn := []*sqlite3.SQLiteConn{}
13 | sql.Register("sqlite3_with_hook_example",
14 | &sqlite3.SQLiteDriver{
15 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
16 | sqlite3conn = append(sqlite3conn, conn)
17 | conn.RegisterUpdateHook(func(op int, db string, table string, rowid int64) {
18 | switch op {
19 | case sqlite3.SQLITE_INSERT:
20 | log.Println("Notified of insert on db", db, "table", table, "rowid", rowid)
21 | }
22 | })
23 | return nil
24 | },
25 | })
26 | os.Remove("./foo.db")
27 | os.Remove("./bar.db")
28 |
29 | srcDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db")
30 | if err != nil {
31 | log.Fatal(err)
32 | }
33 | defer srcDb.Close()
34 | srcDb.Ping()
35 |
36 | _, err = srcDb.Exec("create table foo(id int, value text)")
37 | if err != nil {
38 | log.Fatal(err)
39 | }
40 | _, err = srcDb.Exec("insert into foo values(1, 'foo')")
41 | if err != nil {
42 | log.Fatal(err)
43 | }
44 | _, err = srcDb.Exec("insert into foo values(2, 'bar')")
45 | if err != nil {
46 | log.Fatal(err)
47 | }
48 | _, err = srcDb.Query("select * from foo")
49 | if err != nil {
50 | log.Fatal(err)
51 | }
52 | destDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db")
53 | if err != nil {
54 | log.Fatal(err)
55 | }
56 | defer destDb.Close()
57 | destDb.Ping()
58 |
59 | bk, err := sqlite3conn[1].Backup("main", sqlite3conn[0], "main")
60 | if err != nil {
61 | log.Fatal(err)
62 | }
63 |
64 | _, err = bk.Step(-1)
65 | if err != nil {
66 | log.Fatal(err)
67 | }
68 | _, err = destDb.Query("select * from foo")
69 | if err != nil {
70 | log.Fatal(err)
71 | }
72 | _, err = destDb.Exec("insert into foo values(3, 'bar')")
73 | if err != nil {
74 | log.Fatal(err)
75 | }
76 |
77 | bk.Finish()
78 | }
79 |
--------------------------------------------------------------------------------
/_example/limit/limit.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "os"
8 | "strings"
9 |
10 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
11 | )
12 |
13 | func createBulkInsertQuery(n int, start int) (query string, args []interface{}) {
14 | values := make([]string, n)
15 | args = make([]interface{}, n*2)
16 | pos := 0
17 | for i := 0; i < n; i++ {
18 | values[i] = "(?, ?)"
19 | args[pos] = start + i
20 | args[pos+1] = fmt.Sprintf("こんにちわ世界%03d", i)
21 | pos += 2
22 | }
23 | query = fmt.Sprintf(
24 | "insert into foo(id, name) values %s",
25 | strings.Join(values, ", "),
26 | )
27 | return
28 | }
29 |
30 | func bulkInsert(db *sql.DB, query string, args []interface{}) (err error) {
31 | stmt, err := db.Prepare(query)
32 | if err != nil {
33 | return
34 | }
35 |
36 | _, err = stmt.Exec(args...)
37 | if err != nil {
38 | return
39 | }
40 |
41 | return
42 | }
43 |
44 | func main() {
45 | var sqlite3conn *sqlite3.SQLiteConn
46 | sql.Register("sqlite3_with_limit", &sqlite3.SQLiteDriver{
47 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
48 | sqlite3conn = conn
49 | return nil
50 | },
51 | })
52 |
53 | os.Remove("./foo.db")
54 | db, err := sql.Open("sqlite3_with_limit", "./foo.db")
55 | if err != nil {
56 | log.Fatal(err)
57 | }
58 | defer db.Close()
59 |
60 | sqlStmt := `
61 | create table foo (id integer not null primary key, name text);
62 | delete from foo;
63 | `
64 | _, err = db.Exec(sqlStmt)
65 | if err != nil {
66 | log.Printf("%q: %s\n", err, sqlStmt)
67 | return
68 | }
69 |
70 | if sqlite3conn == nil {
71 | log.Fatal("not set sqlite3 connection")
72 | }
73 |
74 | limitVariableNumber := sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
75 | log.Printf("default SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
76 |
77 | num := 400
78 | query, args := createBulkInsertQuery(num, 0)
79 | err = bulkInsert(db, query, args)
80 | if err != nil {
81 | log.Fatal(err)
82 | }
83 |
84 | smallLimitVariableNumber := 100
85 | sqlite3conn.SetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER, smallLimitVariableNumber)
86 |
87 | limitVariableNumber = sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
88 | log.Printf("updated SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
89 |
90 | query, args = createBulkInsertQuery(num, num)
91 | err = bulkInsert(db, query, args)
92 | if err != nil {
93 | if err != nil {
94 | log.Printf("expect failed since SQLITE_LIMIT_VARIABLE_NUMBER is too small: %v", err)
95 | }
96 | }
97 |
98 | bigLimitVariableNumber := 999999
99 | sqlite3conn.SetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER, bigLimitVariableNumber)
100 | limitVariableNumber = sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
101 | log.Printf("set SQLITE_LIMIT_VARIABLE_NUMBER: %d", bigLimitVariableNumber)
102 | log.Printf("updated SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
103 |
104 | query, args = createBulkInsertQuery(500, num+num)
105 | err = bulkInsert(db, query, args)
106 | if err != nil {
107 | if err != nil {
108 | log.Fatal(err)
109 | }
110 | }
111 |
112 | log.Println("no error if SQLITE_LIMIT_VARIABLE_NUMBER > 999")
113 | }
114 |
--------------------------------------------------------------------------------
/_example/mod_regexp/Makefile:
--------------------------------------------------------------------------------
1 | ifeq ($(OS),Windows_NT)
2 | EXE=extension.exe
3 | LIB_EXT=dll
4 | RM=cmd /c del
5 | LDFLAG=
6 | else
7 | EXE=extension
8 | ifeq ($(shell uname -s),Darwin)
9 | LIB_EXT=dylib
10 | else
11 | LIB_EXT=so
12 | endif
13 | RM=rm -f
14 | LDFLAG=-fPIC
15 | endif
16 | LIB=sqlite3_mod_regexp.$(LIB_EXT)
17 |
18 | all : $(EXE) $(LIB)
19 |
20 | $(EXE) : extension.go
21 | go build $<
22 |
23 | $(LIB) : sqlite3_mod_regexp.c
24 | gcc $(LDFLAG) -shared -o $@ $< -lsqlite3 -lpcre
25 |
26 | clean :
27 | @-$(RM) $(EXE) $(LIB)
28 |
--------------------------------------------------------------------------------
/_example/mod_regexp/extension.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 |
8 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
9 | )
10 |
11 | func main() {
12 | sql.Register("sqlite3_with_extensions",
13 | &sqlite3.SQLiteDriver{
14 | Extensions: []string{
15 | "sqlite3_mod_regexp",
16 | },
17 | })
18 |
19 | db, err := sql.Open("sqlite3_with_extensions", ":memory:")
20 | if err != nil {
21 | log.Fatal(err)
22 | }
23 | defer db.Close()
24 |
25 | // Force db to make a new connection in pool
26 | // by putting the original in a transaction
27 | tx, err := db.Begin()
28 | if err != nil {
29 | log.Fatal(err)
30 | }
31 | defer tx.Commit()
32 |
33 | // New connection works (hopefully!)
34 | rows, err := db.Query("select 'hello world' where 'hello world' regexp '^hello.*d$'")
35 | if err != nil {
36 | log.Fatal(err)
37 | }
38 | defer rows.Close()
39 | for rows.Next() {
40 | var helloworld string
41 | rows.Scan(&helloworld)
42 | fmt.Println(helloworld)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/_example/mod_regexp/sqlite3_mod_regexp.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | SQLITE_EXTENSION_INIT1
7 | static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
8 | if (argc >= 2) {
9 | const char *target = (const char *)sqlite3_value_text(argv[1]);
10 | const char *pattern = (const char *)sqlite3_value_text(argv[0]);
11 | const char* errstr = NULL;
12 | int erroff = 0;
13 | int vec[500];
14 | int n, rc;
15 | pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
16 | if (!re) {
17 | sqlite3_result_error(context, errstr, 0);
18 | return;
19 | }
20 | rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
21 | if (rc <= 0) {
22 | sqlite3_result_int(context, 0);
23 | return;
24 | }
25 | sqlite3_result_int(context, 1);
26 | }
27 | }
28 |
29 | #ifdef _WIN32
30 | __declspec(dllexport)
31 | #endif
32 | int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
33 | SQLITE_EXTENSION_INIT2(api);
34 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL);
35 | }
36 |
--------------------------------------------------------------------------------
/_example/mod_vtable/Makefile:
--------------------------------------------------------------------------------
1 | ifeq ($(OS),Windows_NT)
2 | EXE=extension.exe
3 | LIB_EXT=dll
4 | RM=cmd /c del
5 | LIBCURL=-lcurldll
6 | LDFLAG=
7 | else
8 | EXE=extension
9 | ifeq ($(shell uname -s),Darwin)
10 | LIB_EXT=dylib
11 | else
12 | LIB_EXT=so
13 | endif
14 | RM=rm -f
15 | LDFLAG=-fPIC
16 | LIBCURL=-lcurl
17 | endif
18 | LIB=sqlite3_mod_vtable.$(LIB_EXT)
19 |
20 | all : $(EXE) $(LIB)
21 |
22 | $(EXE) : extension.go
23 | go build $<
24 |
25 | $(LIB) : sqlite3_mod_vtable.cc
26 | g++ $(LDFLAG) -shared -o $@ $< -lsqlite3 $(LIBCURL)
27 |
28 | clean :
29 | @-$(RM) $(EXE) $(LIB)
30 |
--------------------------------------------------------------------------------
/_example/mod_vtable/extension.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 |
8 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
9 | )
10 |
11 | func main() {
12 | sql.Register("sqlite3_with_extensions",
13 | &sqlite3.SQLiteDriver{
14 | Extensions: []string{
15 | "sqlite3_mod_vtable",
16 | },
17 | })
18 |
19 | db, err := sql.Open("sqlite3_with_extensions", ":memory:")
20 | if err != nil {
21 | log.Fatal(err)
22 | }
23 | defer db.Close()
24 |
25 | db.Exec("create virtual table repo using github(id, full_name, description, html_url)")
26 |
27 | rows, err := db.Query("select id, full_name, description, html_url from repo")
28 | if err != nil {
29 | log.Fatal(err)
30 | }
31 | defer rows.Close()
32 | for rows.Next() {
33 | var id, fullName, description, htmlURL string
34 | rows.Scan(&id, &fullName, &description, &htmlURL)
35 | fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/_example/mod_vtable/sqlite3_mod_vtable.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "picojson.h"
7 |
8 | #ifdef _WIN32
9 | # define EXPORT __declspec(dllexport)
10 | #else
11 | # define EXPORT
12 | #endif
13 |
14 | SQLITE_EXTENSION_INIT1;
15 |
16 | typedef struct {
17 | char* data; // response data from server
18 | size_t size; // response size of data
19 | } MEMFILE;
20 |
21 | MEMFILE*
22 | memfopen() {
23 | MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
24 | if (mf) {
25 | mf->data = NULL;
26 | mf->size = 0;
27 | }
28 | return mf;
29 | }
30 |
31 | void
32 | memfclose(MEMFILE* mf) {
33 | if (mf->data) free(mf->data);
34 | free(mf);
35 | }
36 |
37 | size_t
38 | memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
39 | MEMFILE* mf = (MEMFILE*) stream;
40 | int block = size * nmemb;
41 | if (!mf) return block; // through
42 | if (!mf->data)
43 | mf->data = (char*) malloc(block);
44 | else
45 | mf->data = (char*) realloc(mf->data, mf->size + block);
46 | if (mf->data) {
47 | memcpy(mf->data + mf->size, ptr, block);
48 | mf->size += block;
49 | }
50 | return block;
51 | }
52 |
53 | char*
54 | memfstrdup(MEMFILE* mf) {
55 | char* buf;
56 | if (mf->size == 0) return NULL;
57 | buf = (char*) malloc(mf->size + 1);
58 | memcpy(buf, mf->data, mf->size);
59 | buf[mf->size] = 0;
60 | return buf;
61 | }
62 |
63 | static int
64 | my_connect(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **c) {
65 | std::stringstream ss;
66 | ss << "CREATE TABLE " << argv[0]
67 | << "(id int, full_name text, description text, html_url text)";
68 | int rc = sqlite3_declare_vtab(db, ss.str().c_str());
69 | *ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
70 | memset(*ppVTab, 0, sizeof(sqlite3_vtab));
71 | return rc;
72 | }
73 |
74 | static int
75 | my_create(sqlite3 *db, void *pAux, int argc, const char * const * argv, sqlite3_vtab **ppVTab, char **c) {
76 | return my_connect(db, pAux, argc, argv, ppVTab, c);
77 | }
78 |
79 | static int my_disconnect(sqlite3_vtab *pVTab) {
80 | sqlite3_free(pVTab);
81 | return SQLITE_OK;
82 | }
83 |
84 | static int
85 | my_destroy(sqlite3_vtab *pVTab) {
86 | sqlite3_free(pVTab);
87 | return SQLITE_OK;
88 | }
89 |
90 | typedef struct {
91 | sqlite3_vtab_cursor base;
92 | int index;
93 | picojson::value* rows;
94 | } cursor;
95 |
96 | static int
97 | my_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
98 | MEMFILE* mf;
99 | CURL* curl;
100 | char* json;
101 | CURLcode res = CURLE_OK;
102 | char error[CURL_ERROR_SIZE] = {0};
103 | char* cert_file = getenv("SSL_CERT_FILE");
104 |
105 | mf = memfopen();
106 | curl = curl_easy_init();
107 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
108 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
109 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.29.0");
110 | curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repositories");
111 | if (cert_file)
112 | curl_easy_setopt(curl, CURLOPT_CAINFO, cert_file);
113 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
114 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
115 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
116 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
117 | res = curl_easy_perform(curl);
118 | curl_easy_cleanup(curl);
119 | if (res != CURLE_OK) {
120 | std::cerr << error << std::endl;
121 | return SQLITE_FAIL;
122 | }
123 |
124 | picojson::value* v = new picojson::value;
125 | std::string err;
126 | picojson::parse(*v, mf->data, mf->data + mf->size, &err);
127 | memfclose(mf);
128 |
129 | if (!err.empty()) {
130 | delete v;
131 | std::cerr << err << std::endl;
132 | return SQLITE_FAIL;
133 | }
134 |
135 | cursor *c = (cursor *)sqlite3_malloc(sizeof(cursor));
136 | c->rows = v;
137 | c->index = 0;
138 | *ppCursor = &c->base;
139 | return SQLITE_OK;
140 | }
141 |
142 | static int
143 | my_close(cursor *c) {
144 | delete c->rows;
145 | sqlite3_free(c);
146 | return SQLITE_OK;
147 | }
148 |
149 | static int
150 | my_filter(cursor *c, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
151 | c->index = 0;
152 | return SQLITE_OK;
153 | }
154 |
155 | static int
156 | my_next(cursor *c) {
157 | c->index++;
158 | return SQLITE_OK;
159 | }
160 |
161 | static int
162 | my_eof(cursor *c) {
163 | return c->index >= c->rows->get().size() ? 1 : 0;
164 | }
165 |
166 | static int
167 | my_column(cursor *c, sqlite3_context *ctxt, int i) {
168 | picojson::value v = c->rows->get()[c->index];
169 | picojson::object row = v.get();
170 | const char* p = NULL;
171 | switch (i) {
172 | case 0:
173 | p = row["id"].to_str().c_str();
174 | break;
175 | case 1:
176 | p = row["full_name"].to_str().c_str();
177 | break;
178 | case 2:
179 | p = row["description"].to_str().c_str();
180 | break;
181 | case 3:
182 | p = row["html_url"].to_str().c_str();
183 | break;
184 | }
185 | sqlite3_result_text(ctxt, strdup(p), strlen(p), free);
186 | return SQLITE_OK;
187 | }
188 |
189 | static int
190 | my_rowid(cursor *c, sqlite3_int64 *pRowid) {
191 | *pRowid = c->index;
192 | return SQLITE_OK;
193 | }
194 |
195 | static int
196 | my_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {
197 | return SQLITE_OK;
198 | }
199 |
200 | static const sqlite3_module module = {
201 | 0,
202 | my_create,
203 | my_connect,
204 | my_bestindex,
205 | my_disconnect,
206 | my_destroy,
207 | my_open,
208 | (int (*)(sqlite3_vtab_cursor *)) my_close,
209 | (int (*)(sqlite3_vtab_cursor *, int, char const *, int, sqlite3_value **)) my_filter,
210 | (int (*)(sqlite3_vtab_cursor *)) my_next,
211 | (int (*)(sqlite3_vtab_cursor *)) my_eof,
212 | (int (*)(sqlite3_vtab_cursor *, sqlite3_context *, int)) my_column,
213 | (int (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) my_rowid,
214 | NULL, // my_update
215 | NULL, // my_begin
216 | NULL, // my_sync
217 | NULL, // my_commit
218 | NULL, // my_rollback
219 | NULL, // my_findfunction
220 | NULL, // my_rename
221 | };
222 |
223 | static void
224 | destructor(void *arg) {
225 | return;
226 | }
227 |
228 |
229 | extern "C" {
230 |
231 | EXPORT int
232 | sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
233 | SQLITE_EXTENSION_INIT2(api);
234 | sqlite3_create_module_v2(db, "github", &module, NULL, destructor);
235 | return 0;
236 | }
237 |
238 | }
239 |
--------------------------------------------------------------------------------
/_example/simple/simple.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "os"
8 |
9 | _ "github.com/mutecomm/go-sqlcipher/v4"
10 | )
11 |
12 | func main() {
13 | os.Remove("./foo.db")
14 |
15 | db, err := sql.Open("sqlite3", "./foo.db")
16 | if err != nil {
17 | log.Fatal(err)
18 | }
19 | defer db.Close()
20 |
21 | sqlStmt := `
22 | create table foo (id integer not null primary key, name text);
23 | delete from foo;
24 | `
25 | _, err = db.Exec(sqlStmt)
26 | if err != nil {
27 | log.Printf("%q: %s\n", err, sqlStmt)
28 | return
29 | }
30 |
31 | tx, err := db.Begin()
32 | if err != nil {
33 | log.Fatal(err)
34 | }
35 | stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
36 | if err != nil {
37 | log.Fatal(err)
38 | }
39 | defer stmt.Close()
40 | for i := 0; i < 100; i++ {
41 | _, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
42 | if err != nil {
43 | log.Fatal(err)
44 | }
45 | }
46 | tx.Commit()
47 |
48 | rows, err := db.Query("select id, name from foo")
49 | if err != nil {
50 | log.Fatal(err)
51 | }
52 | defer rows.Close()
53 | for rows.Next() {
54 | var id int
55 | var name string
56 | err = rows.Scan(&id, &name)
57 | if err != nil {
58 | log.Fatal(err)
59 | }
60 | fmt.Println(id, name)
61 | }
62 | err = rows.Err()
63 | if err != nil {
64 | log.Fatal(err)
65 | }
66 |
67 | stmt, err = db.Prepare("select name from foo where id = ?")
68 | if err != nil {
69 | log.Fatal(err)
70 | }
71 | defer stmt.Close()
72 | var name string
73 | err = stmt.QueryRow("3").Scan(&name)
74 | if err != nil {
75 | log.Fatal(err)
76 | }
77 | fmt.Println(name)
78 |
79 | _, err = db.Exec("delete from foo")
80 | if err != nil {
81 | log.Fatal(err)
82 | }
83 |
84 | _, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')")
85 | if err != nil {
86 | log.Fatal(err)
87 | }
88 |
89 | rows, err = db.Query("select id, name from foo")
90 | if err != nil {
91 | log.Fatal(err)
92 | }
93 | defer rows.Close()
94 | for rows.Next() {
95 | var id int
96 | var name string
97 | err = rows.Scan(&id, &name)
98 | if err != nil {
99 | log.Fatal(err)
100 | }
101 | fmt.Println(id, name)
102 | }
103 | err = rows.Err()
104 | if err != nil {
105 | log.Fatal(err)
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/_example/trace/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "os"
8 |
9 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
10 | )
11 |
12 | func traceCallback(info sqlite3.TraceInfo) int {
13 | // Not very readable but may be useful; uncomment next line in case of doubt:
14 | //fmt.Printf("Trace: %#v\n", info)
15 |
16 | var dbErrText string
17 | if info.DBError.Code != 0 || info.DBError.ExtendedCode != 0 {
18 | dbErrText = fmt.Sprintf("; DB error: %#v", info.DBError)
19 | } else {
20 | dbErrText = "."
21 | }
22 |
23 | // Show the Statement-or-Trigger text in curly braces ('{', '}')
24 | // since from the *paired* ASCII characters they are
25 | // the least used in SQL syntax, therefore better visual delimiters.
26 | // Maybe show 'ExpandedSQL' the same way as 'StmtOrTrigger'.
27 | //
28 | // A known use of curly braces (outside strings) is
29 | // for ODBC escape sequences. Not likely to appear here.
30 | //
31 | // Template languages, etc. don't matter, we should see their *result*
32 | // at *this* level.
33 | // Strange curly braces in SQL code that reached the database driver
34 | // suggest that there is a bug in the application.
35 | // The braces are likely to be either template syntax or
36 | // a programming language's string interpolation syntax.
37 |
38 | var expandedText string
39 | if info.ExpandedSQL != "" {
40 | if info.ExpandedSQL == info.StmtOrTrigger {
41 | expandedText = " = exp"
42 | } else {
43 | expandedText = fmt.Sprintf(" expanded {%q}", info.ExpandedSQL)
44 | }
45 | } else {
46 | expandedText = ""
47 | }
48 |
49 | // SQLite docs as of September 6, 2016: Tracing and Profiling Functions
50 | // https://www.sqlite.org/c3ref/profile.html
51 | //
52 | // The profile callback time is in units of nanoseconds, however
53 | // the current implementation is only capable of millisecond resolution
54 | // so the six least significant digits in the time are meaningless.
55 | // Future versions of SQLite might provide greater resolution on the profiler callback.
56 |
57 | var runTimeText string
58 | if info.RunTimeNanosec == 0 {
59 | if info.EventCode == sqlite3.TraceProfile {
60 | //runTimeText = "; no time" // seems confusing
61 | runTimeText = "; time 0" // no measurement unit
62 | } else {
63 | //runTimeText = "; no time" // seems useless and confusing
64 | }
65 | } else {
66 | const nanosPerMillisec = 1000000
67 | if info.RunTimeNanosec%nanosPerMillisec == 0 {
68 | runTimeText = fmt.Sprintf("; time %d ms", info.RunTimeNanosec/nanosPerMillisec)
69 | } else {
70 | // unexpected: better than millisecond resolution
71 | runTimeText = fmt.Sprintf("; time %d ns!!!", info.RunTimeNanosec)
72 | }
73 | }
74 |
75 | var modeText string
76 | if info.AutoCommit {
77 | modeText = "-AC-"
78 | } else {
79 | modeText = "+Tx+"
80 | }
81 |
82 | fmt.Printf("Trace: ev %d %s conn 0x%x, stmt 0x%x {%q}%s%s%s\n",
83 | info.EventCode, modeText, info.ConnHandle, info.StmtHandle,
84 | info.StmtOrTrigger, expandedText,
85 | runTimeText,
86 | dbErrText)
87 | return 0
88 | }
89 |
90 | func main() {
91 | eventMask := sqlite3.TraceStmt | sqlite3.TraceProfile | sqlite3.TraceRow | sqlite3.TraceClose
92 |
93 | sql.Register("sqlite3_tracing",
94 | &sqlite3.SQLiteDriver{
95 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
96 | err := conn.SetTrace(&sqlite3.TraceConfig{
97 | Callback: traceCallback,
98 | EventMask: eventMask,
99 | WantExpandedSQL: true,
100 | })
101 | return err
102 | },
103 | })
104 |
105 | os.Exit(dbMain())
106 | }
107 |
108 | // Harder to do DB work in main().
109 | // It's better with a separate function because
110 | // 'defer' and 'os.Exit' don't go well together.
111 | //
112 | // DO NOT use 'log.Fatal...' below: remember that it's equivalent to
113 | // Print() followed by a call to os.Exit(1) --- and
114 | // we want to avoid Exit() so 'defer' can do cleanup.
115 | // Use 'log.Panic...' instead.
116 |
117 | func dbMain() int {
118 | db, err := sql.Open("sqlite3_tracing", ":memory:")
119 | if err != nil {
120 | fmt.Printf("Failed to open database: %#+v\n", err)
121 | return 1
122 | }
123 | defer db.Close()
124 |
125 | err = db.Ping()
126 | if err != nil {
127 | log.Panic(err)
128 | }
129 |
130 | dbSetup(db)
131 |
132 | dbDoInsert(db)
133 | dbDoInsertPrepared(db)
134 | dbDoSelect(db)
135 | dbDoSelectPrepared(db)
136 |
137 | return 0
138 | }
139 |
140 | // 'DDL' stands for "Data Definition Language":
141 |
142 | // Note: "INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT" causes the error
143 | // 'near "AUTOINCREMENT": syntax error'; without "NOT NULL" it works.
144 | const tableDDL = `CREATE TABLE t1 (
145 | id INTEGER PRIMARY KEY AUTOINCREMENT,
146 | note VARCHAR NOT NULL
147 | )`
148 |
149 | // 'DML' stands for "Data Manipulation Language":
150 |
151 | const insertDML = "INSERT INTO t1 (note) VALUES (?)"
152 | const selectDML = "SELECT id, note FROM t1 WHERE note LIKE ?"
153 |
154 | const textPrefix = "bla-1234567890-"
155 | const noteTextPattern = "%Prep%"
156 |
157 | const nGenRows = 4 // Number of Rows to Generate (for *each* approach tested)
158 |
159 | func dbSetup(db *sql.DB) {
160 | var err error
161 |
162 | _, err = db.Exec("DROP TABLE IF EXISTS t1")
163 | if err != nil {
164 | log.Panic(err)
165 | }
166 | _, err = db.Exec(tableDDL)
167 | if err != nil {
168 | log.Panic(err)
169 | }
170 | }
171 |
172 | func dbDoInsert(db *sql.DB) {
173 | const Descr = "DB-Exec"
174 | for i := 0; i < nGenRows; i++ {
175 | result, err := db.Exec(insertDML, textPrefix+Descr)
176 | if err != nil {
177 | log.Panic(err)
178 | }
179 |
180 | resultDoCheck(result, Descr, i)
181 | }
182 | }
183 |
184 | func dbDoInsertPrepared(db *sql.DB) {
185 | const Descr = "DB-Prepare"
186 |
187 | stmt, err := db.Prepare(insertDML)
188 | if err != nil {
189 | log.Panic(err)
190 | }
191 | defer stmt.Close()
192 |
193 | for i := 0; i < nGenRows; i++ {
194 | result, err := stmt.Exec(textPrefix + Descr)
195 | if err != nil {
196 | log.Panic(err)
197 | }
198 |
199 | resultDoCheck(result, Descr, i)
200 | }
201 | }
202 |
203 | func resultDoCheck(result sql.Result, callerDescr string, callIndex int) {
204 | lastID, err := result.LastInsertId()
205 | if err != nil {
206 | log.Panic(err)
207 | }
208 | nAffected, err := result.RowsAffected()
209 | if err != nil {
210 | log.Panic(err)
211 | }
212 |
213 | log.Printf("Exec result for %s (%d): ID = %d, affected = %d\n", callerDescr, callIndex, lastID, nAffected)
214 | }
215 |
216 | func dbDoSelect(db *sql.DB) {
217 | const Descr = "DB-Query"
218 |
219 | rows, err := db.Query(selectDML, noteTextPattern)
220 | if err != nil {
221 | log.Panic(err)
222 | }
223 | defer rows.Close()
224 |
225 | rowsDoFetch(rows, Descr)
226 | }
227 |
228 | func dbDoSelectPrepared(db *sql.DB) {
229 | const Descr = "DB-Prepare"
230 |
231 | stmt, err := db.Prepare(selectDML)
232 | if err != nil {
233 | log.Panic(err)
234 | }
235 | defer stmt.Close()
236 |
237 | rows, err := stmt.Query(noteTextPattern)
238 | if err != nil {
239 | log.Panic(err)
240 | }
241 | defer rows.Close()
242 |
243 | rowsDoFetch(rows, Descr)
244 | }
245 |
246 | func rowsDoFetch(rows *sql.Rows, callerDescr string) {
247 | var nRows int
248 | var id int64
249 | var note string
250 |
251 | for rows.Next() {
252 | err := rows.Scan(&id, ¬e)
253 | if err != nil {
254 | log.Panic(err)
255 | }
256 | log.Printf("Row for %s (%d): id=%d, note=%q\n",
257 | callerDescr, nRows, id, note)
258 | nRows++
259 | }
260 | if err := rows.Err(); err != nil {
261 | log.Panic(err)
262 | }
263 | log.Printf("Total %d rows for %s.\n", nRows, callerDescr)
264 | }
265 |
--------------------------------------------------------------------------------
/_example/vtable/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 |
8 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
9 | )
10 |
11 | func main() {
12 | sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{
13 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
14 | return conn.CreateModule("github", &githubModule{})
15 | },
16 | })
17 | db, err := sql.Open("sqlite3_with_extensions", ":memory:")
18 | if err != nil {
19 | log.Fatal(err)
20 | }
21 | defer db.Close()
22 |
23 | _, err = db.Exec("create virtual table repo using github(id, full_name, description, html_url)")
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 |
28 | rows, err := db.Query("select id, full_name, description, html_url from repo")
29 | if err != nil {
30 | log.Fatal(err)
31 | }
32 | defer rows.Close()
33 | for rows.Next() {
34 | var id, fullName, description, htmlURL string
35 | rows.Scan(&id, &fullName, &description, &htmlURL)
36 | fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/_example/vtable/vtable.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "net/http"
8 |
9 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
10 | )
11 |
12 | type githubRepo struct {
13 | ID int `json:"id"`
14 | FullName string `json:"full_name"`
15 | Description string `json:"description"`
16 | HTMLURL string `json:"html_url"`
17 | }
18 |
19 | type githubModule struct {
20 | }
21 |
22 | func (m *githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) {
23 | err := c.DeclareVTab(fmt.Sprintf(`
24 | CREATE TABLE %s (
25 | id INT,
26 | full_name TEXT,
27 | description TEXT,
28 | html_url TEXT
29 | )`, args[0]))
30 | if err != nil {
31 | return nil, err
32 | }
33 | return &ghRepoTable{}, nil
34 | }
35 |
36 | func (m *githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) {
37 | return m.Create(c, args)
38 | }
39 |
40 | func (m *githubModule) DestroyModule() {}
41 |
42 | type ghRepoTable struct {
43 | repos []githubRepo
44 | }
45 |
46 | func (v *ghRepoTable) Open() (sqlite3.VTabCursor, error) {
47 | resp, err := http.Get("https://api.github.com/repositories")
48 | if err != nil {
49 | return nil, err
50 | }
51 | defer resp.Body.Close()
52 |
53 | body, err := ioutil.ReadAll(resp.Body)
54 | if err != nil {
55 | return nil, err
56 | }
57 |
58 | var repos []githubRepo
59 | if err := json.Unmarshal(body, &repos); err != nil {
60 | return nil, err
61 | }
62 | return &ghRepoCursor{0, repos}, nil
63 | }
64 |
65 | func (v *ghRepoTable) BestIndex(cst []sqlite3.InfoConstraint, ob []sqlite3.InfoOrderBy) (*sqlite3.IndexResult, error) {
66 | return &sqlite3.IndexResult{}, nil
67 | }
68 |
69 | func (v *ghRepoTable) Disconnect() error { return nil }
70 | func (v *ghRepoTable) Destroy() error { return nil }
71 |
72 | type ghRepoCursor struct {
73 | index int
74 | repos []githubRepo
75 | }
76 |
77 | func (vc *ghRepoCursor) Column(c *sqlite3.SQLiteContext, col int) error {
78 | switch col {
79 | case 0:
80 | c.ResultInt(vc.repos[vc.index].ID)
81 | case 1:
82 | c.ResultText(vc.repos[vc.index].FullName)
83 | case 2:
84 | c.ResultText(vc.repos[vc.index].Description)
85 | case 3:
86 | c.ResultText(vc.repos[vc.index].HTMLURL)
87 | }
88 | return nil
89 | }
90 |
91 | func (vc *ghRepoCursor) Filter(idxNum int, idxStr string, vals []interface{}) error {
92 | vc.index = 0
93 | return nil
94 | }
95 |
96 | func (vc *ghRepoCursor) Next() error {
97 | vc.index++
98 | return nil
99 | }
100 |
101 | func (vc *ghRepoCursor) EOF() bool {
102 | return vc.index >= len(vc.repos)
103 | }
104 |
105 | func (vc *ghRepoCursor) Rowid() (int64, error) {
106 | return int64(vc.index), nil
107 | }
108 |
109 | func (vc *ghRepoCursor) Close() error {
110 | return nil
111 | }
112 |
--------------------------------------------------------------------------------
/backup.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | /*
9 | #ifndef USE_LIBSQLITE3
10 | #include
11 | #else
12 | #include
13 | #endif
14 | #include
15 | */
16 | import "C"
17 | import (
18 | "runtime"
19 | "unsafe"
20 | )
21 |
22 | // SQLiteBackup implement interface of Backup.
23 | type SQLiteBackup struct {
24 | b *C.sqlite3_backup
25 | }
26 |
27 | // Backup make backup from src to dest.
28 | func (destConn *SQLiteConn) Backup(dest string, srcConn *SQLiteConn, src string) (*SQLiteBackup, error) {
29 | destptr := C.CString(dest)
30 | defer C.free(unsafe.Pointer(destptr))
31 | srcptr := C.CString(src)
32 | defer C.free(unsafe.Pointer(srcptr))
33 |
34 | if b := C.sqlite3_backup_init(destConn.db, destptr, srcConn.db, srcptr); b != nil {
35 | bb := &SQLiteBackup{b: b}
36 | runtime.SetFinalizer(bb, (*SQLiteBackup).Finish)
37 | return bb, nil
38 | }
39 | return nil, destConn.lastError()
40 | }
41 |
42 | // Step to backs up for one step. Calls the underlying `sqlite3_backup_step`
43 | // function. This function returns a boolean indicating if the backup is done
44 | // and an error signalling any other error. Done is returned if the underlying
45 | // C function returns SQLITE_DONE (Code 101)
46 | func (b *SQLiteBackup) Step(p int) (bool, error) {
47 | ret := C.sqlite3_backup_step(b.b, C.int(p))
48 | if ret == C.SQLITE_DONE {
49 | return true, nil
50 | } else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY {
51 | return false, Error{Code: ErrNo(ret)}
52 | }
53 | return false, nil
54 | }
55 |
56 | // Remaining return whether have the rest for backup.
57 | func (b *SQLiteBackup) Remaining() int {
58 | return int(C.sqlite3_backup_remaining(b.b))
59 | }
60 |
61 | // PageCount return count of pages.
62 | func (b *SQLiteBackup) PageCount() int {
63 | return int(C.sqlite3_backup_pagecount(b.b))
64 | }
65 |
66 | // Finish close backup.
67 | func (b *SQLiteBackup) Finish() error {
68 | return b.Close()
69 | }
70 |
71 | // Close close backup.
72 | func (b *SQLiteBackup) Close() error {
73 | ret := C.sqlite3_backup_finish(b.b)
74 |
75 | // sqlite3_backup_finish() never fails, it just returns the
76 | // error code from previous operations, so clean up before
77 | // checking and returning an error
78 | b.b = nil
79 | runtime.SetFinalizer(b, nil)
80 |
81 | if ret != 0 {
82 | return Error{Code: ErrNo(ret)}
83 | }
84 | return nil
85 | }
86 |
--------------------------------------------------------------------------------
/burn_stack.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file burn_stack.c
7 | Burn stack, Tom St Denis
8 | */
9 |
10 | /**
11 | Burn some stack memory
12 | @param len amount of stack to burn in bytes
13 | */
14 | void burn_stack(unsigned long len)
15 | {
16 | unsigned char buf[32];
17 | zeromem(buf, sizeof(buf));
18 | if (len > (unsigned long)sizeof(buf)) {
19 | burn_stack(len - sizeof(buf));
20 | }
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/callback_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 |
8 | package sqlite3
9 |
10 | import (
11 | "errors"
12 | "math"
13 | "reflect"
14 | "testing"
15 | )
16 |
17 | func TestCallbackArgCast(t *testing.T) {
18 | intConv := callbackSyntheticForTests(reflect.ValueOf(int64(math.MaxInt64)), nil)
19 | floatConv := callbackSyntheticForTests(reflect.ValueOf(float64(math.MaxFloat64)), nil)
20 | errConv := callbackSyntheticForTests(reflect.Value{}, errors.New("test"))
21 |
22 | tests := []struct {
23 | f callbackArgConverter
24 | o reflect.Value
25 | }{
26 | {intConv, reflect.ValueOf(int8(-1))},
27 | {intConv, reflect.ValueOf(int16(-1))},
28 | {intConv, reflect.ValueOf(int32(-1))},
29 | {intConv, reflect.ValueOf(uint8(math.MaxUint8))},
30 | {intConv, reflect.ValueOf(uint16(math.MaxUint16))},
31 | {intConv, reflect.ValueOf(uint32(math.MaxUint32))},
32 | // Special case, int64->uint64 is only 1<<63 - 1, not 1<<64 - 1
33 | {intConv, reflect.ValueOf(uint64(math.MaxInt64))},
34 | {floatConv, reflect.ValueOf(float32(math.Inf(1)))},
35 | }
36 |
37 | for _, test := range tests {
38 | conv := callbackArgCast{test.f, test.o.Type()}
39 | val, err := conv.Run(nil)
40 | if err != nil {
41 | t.Errorf("Couldn't convert to %s: %s", test.o.Type(), err)
42 | } else if !reflect.DeepEqual(val.Interface(), test.o.Interface()) {
43 | t.Errorf("Unexpected result from converting to %s: got %v, want %v", test.o.Type(), val.Interface(), test.o.Interface())
44 | }
45 | }
46 |
47 | conv := callbackArgCast{errConv, reflect.TypeOf(int8(0))}
48 | _, err := conv.Run(nil)
49 | if err == nil {
50 | t.Errorf("Expected error during callbackArgCast, but got none")
51 | }
52 | }
53 |
54 | func TestCallbackConverters(t *testing.T) {
55 | tests := []struct {
56 | v interface{}
57 | err bool
58 | }{
59 | // Unfortunately, we can't tell which converter was returned,
60 | // but we can at least check which types can be converted.
61 | {[]byte{0}, false},
62 | {"text", false},
63 | {true, false},
64 | {int8(0), false},
65 | {int16(0), false},
66 | {int32(0), false},
67 | {int64(0), false},
68 | {uint8(0), false},
69 | {uint16(0), false},
70 | {uint32(0), false},
71 | {uint64(0), false},
72 | {int(0), false},
73 | {uint(0), false},
74 | {float64(0), false},
75 | {float32(0), false},
76 |
77 | {func() {}, true},
78 | {complex64(complex(0, 0)), true},
79 | {complex128(complex(0, 0)), true},
80 | {struct{}{}, true},
81 | {map[string]string{}, true},
82 | {[]string{}, true},
83 | {(*int8)(nil), true},
84 | {make(chan int), true},
85 | }
86 |
87 | for _, test := range tests {
88 | _, err := callbackArg(reflect.TypeOf(test.v))
89 | if test.err && err == nil {
90 | t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
91 | } else if !test.err && err != nil {
92 | t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
93 | }
94 | }
95 |
96 | for _, test := range tests {
97 | _, err := callbackRet(reflect.TypeOf(test.v))
98 | if test.err && err == nil {
99 | t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
100 | } else if !test.err && err != nil {
101 | t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/cbc_decrypt.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file cbc_decrypt.c
7 | CBC implementation, encrypt block, Tom St Denis
8 | */
9 |
10 |
11 | #ifdef LTC_CBC_MODE
12 |
13 | /**
14 | CBC decrypt
15 | @param ct Ciphertext
16 | @param pt [out] Plaintext
17 | @param len The number of bytes to process (must be multiple of block length)
18 | @param cbc CBC state
19 | @return CRYPT_OK if successful
20 | */
21 | int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc)
22 | {
23 | int x, err;
24 | unsigned char tmp[16];
25 | #ifdef LTC_FAST
26 | LTC_FAST_TYPE tmpy;
27 | #else
28 | unsigned char tmpy;
29 | #endif
30 |
31 | LTC_ARGCHK(pt != NULL);
32 | LTC_ARGCHK(ct != NULL);
33 | LTC_ARGCHK(cbc != NULL);
34 |
35 | if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
36 | return err;
37 | }
38 |
39 | /* is blocklen valid? */
40 | if (cbc->blocklen < 1 || cbc->blocklen > (int)sizeof(cbc->IV) || cbc->blocklen > (int)sizeof(tmp)) {
41 | return CRYPT_INVALID_ARG;
42 | }
43 |
44 | if (len % cbc->blocklen) {
45 | return CRYPT_INVALID_ARG;
46 | }
47 | #ifdef LTC_FAST
48 | if (cbc->blocklen % sizeof(LTC_FAST_TYPE)) {
49 | return CRYPT_INVALID_ARG;
50 | }
51 | #endif
52 |
53 | if (cipher_descriptor[cbc->cipher].accel_cbc_decrypt != NULL) {
54 | return cipher_descriptor[cbc->cipher].accel_cbc_decrypt(ct, pt, len / cbc->blocklen, cbc->IV, &cbc->key);
55 | }
56 | while (len) {
57 | /* decrypt */
58 | if ((err = cipher_descriptor[cbc->cipher].ecb_decrypt(ct, tmp, &cbc->key)) != CRYPT_OK) {
59 | return err;
60 | }
61 |
62 | /* xor IV against plaintext */
63 | #if defined(LTC_FAST)
64 | for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
65 | tmpy = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) ^ *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)tmp + x));
66 | *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x));
67 | *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x)) = tmpy;
68 | }
69 | #else
70 | for (x = 0; x < cbc->blocklen; x++) {
71 | tmpy = tmp[x] ^ cbc->IV[x];
72 | cbc->IV[x] = ct[x];
73 | pt[x] = tmpy;
74 | }
75 | #endif
76 |
77 | ct += cbc->blocklen;
78 | pt += cbc->blocklen;
79 | len -= cbc->blocklen;
80 | }
81 | return CRYPT_OK;
82 | }
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/cbc_done.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file cbc_done.c
7 | CBC implementation, finish chain, Tom St Denis
8 | */
9 |
10 | #ifdef LTC_CBC_MODE
11 |
12 | /** Terminate the chain
13 | @param cbc The CBC chain to terminate
14 | @return CRYPT_OK on success
15 | */
16 | int cbc_done(symmetric_CBC *cbc)
17 | {
18 | int err;
19 | LTC_ARGCHK(cbc != NULL);
20 |
21 | if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
22 | return err;
23 | }
24 | cipher_descriptor[cbc->cipher].done(&cbc->key);
25 | return CRYPT_OK;
26 | }
27 |
28 |
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/cbc_encrypt.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file cbc_encrypt.c
7 | CBC implementation, encrypt block, Tom St Denis
8 | */
9 |
10 |
11 | #ifdef LTC_CBC_MODE
12 |
13 | /**
14 | CBC encrypt
15 | @param pt Plaintext
16 | @param ct [out] Ciphertext
17 | @param len The number of bytes to process (must be multiple of block length)
18 | @param cbc CBC state
19 | @return CRYPT_OK if successful
20 | */
21 | int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc)
22 | {
23 | int x, err;
24 |
25 | LTC_ARGCHK(pt != NULL);
26 | LTC_ARGCHK(ct != NULL);
27 | LTC_ARGCHK(cbc != NULL);
28 |
29 | if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
30 | return err;
31 | }
32 |
33 | /* is blocklen valid? */
34 | if (cbc->blocklen < 1 || cbc->blocklen > (int)sizeof(cbc->IV)) {
35 | return CRYPT_INVALID_ARG;
36 | }
37 |
38 | if (len % cbc->blocklen) {
39 | return CRYPT_INVALID_ARG;
40 | }
41 | #ifdef LTC_FAST
42 | if (cbc->blocklen % sizeof(LTC_FAST_TYPE)) {
43 | return CRYPT_INVALID_ARG;
44 | }
45 | #endif
46 |
47 | if (cipher_descriptor[cbc->cipher].accel_cbc_encrypt != NULL) {
48 | return cipher_descriptor[cbc->cipher].accel_cbc_encrypt(pt, ct, len / cbc->blocklen, cbc->IV, &cbc->key);
49 | }
50 | while (len) {
51 | /* xor IV against plaintext */
52 | #if defined(LTC_FAST)
53 | for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
54 | *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) ^= *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x));
55 | }
56 | #else
57 | for (x = 0; x < cbc->blocklen; x++) {
58 | cbc->IV[x] ^= pt[x];
59 | }
60 | #endif
61 |
62 | /* encrypt */
63 | if ((err = cipher_descriptor[cbc->cipher].ecb_encrypt(cbc->IV, ct, &cbc->key)) != CRYPT_OK) {
64 | return err;
65 | }
66 |
67 | /* store IV [ciphertext] for a future block */
68 | #if defined(LTC_FAST)
69 | for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
70 | *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x));
71 | }
72 | #else
73 | for (x = 0; x < cbc->blocklen; x++) {
74 | cbc->IV[x] = ct[x];
75 | }
76 | #endif
77 |
78 | ct += cbc->blocklen;
79 | pt += cbc->blocklen;
80 | len -= cbc->blocklen;
81 | }
82 | return CRYPT_OK;
83 | }
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/cbc_start.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file cbc_start.c
7 | CBC implementation, start chain, Tom St Denis
8 | */
9 |
10 | #ifdef LTC_CBC_MODE
11 |
12 | /**
13 | Initialize a CBC context
14 | @param cipher The index of the cipher desired
15 | @param IV The initialization vector
16 | @param key The secret key
17 | @param keylen The length of the secret key (octets)
18 | @param num_rounds Number of rounds in the cipher desired (0 for default)
19 | @param cbc The CBC state to initialize
20 | @return CRYPT_OK if successful
21 | */
22 | int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
23 | int keylen, int num_rounds, symmetric_CBC *cbc)
24 | {
25 | int x, err;
26 |
27 | LTC_ARGCHK(IV != NULL);
28 | LTC_ARGCHK(key != NULL);
29 | LTC_ARGCHK(cbc != NULL);
30 |
31 | /* bad param? */
32 | if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
33 | return err;
34 | }
35 |
36 | /* setup cipher */
37 | if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cbc->key)) != CRYPT_OK) {
38 | return err;
39 | }
40 |
41 | /* copy IV */
42 | cbc->blocklen = cipher_descriptor[cipher].block_length;
43 | cbc->cipher = cipher;
44 | for (x = 0; x < cbc->blocklen; x++) {
45 | cbc->IV[x] = IV[x];
46 | }
47 | return CRYPT_OK;
48 | }
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/compare_testvector.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 |
4 | #include "tomcrypt_private.h"
5 |
6 | /**
7 | @file compare_testvector.c
8 | Function to compare two testvectors and print a (detailed) error-message if required, Steffen Jaeckel
9 | */
10 |
11 | #if defined(LTC_TEST) && defined(LTC_TEST_DBG)
12 | static void s_print_hex(const char* what, const void* v, const unsigned long l)
13 | {
14 | const unsigned char* p = v;
15 | unsigned long x, y = 0, z;
16 | fprintf(stderr, "%s contents: \n", what);
17 | for (x = 0; x < l; ) {
18 | fprintf(stderr, "%02X ", p[x]);
19 | if (!(++x % 16) || x == l) {
20 | if((x % 16) != 0) {
21 | z = 16 - (x % 16);
22 | if(z >= 8)
23 | fprintf(stderr, " ");
24 | for (; z != 0; --z) {
25 | fprintf(stderr, " ");
26 | }
27 | }
28 | fprintf(stderr, " | ");
29 | for(; y < x; y++) {
30 | if((y % 8) == 0)
31 | fprintf(stderr, " ");
32 | if(isgraph(p[y]))
33 | fprintf(stderr, "%c", p[y]);
34 | else
35 | fprintf(stderr, ".");
36 | }
37 | fprintf(stderr, "\n");
38 | }
39 | else if((x % 8) == 0) {
40 | fprintf(stderr, " ");
41 | }
42 | }
43 | }
44 | #endif
45 |
46 | /**
47 | Compare two test-vectors
48 |
49 | @param is The data as it is
50 | @param is_len The length of is
51 | @param should The data as it should
52 | @param should_len The length of should
53 | @param what The type of the data
54 | @param which The iteration count
55 | @return 0 on equality, -1 or 1 on difference
56 | */
57 | int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which)
58 | {
59 | int res = 0;
60 | if(is_len != should_len) {
61 | res = is_len > should_len ? -1 : 1;
62 | } else {
63 | res = XMEMCMP(is, should, is_len);
64 | }
65 | #if defined(LTC_TEST) && defined(LTC_TEST_DBG)
66 | if (res != 0) {
67 | fprintf(stderr, "Testvector #%i of %s failed:\n", which, what);
68 | s_print_hex("SHOULD", should, should_len);
69 | s_print_hex("IS ", is, is_len);
70 | #if LTC_TEST_DBG > 1
71 | } else {
72 | fprintf(stderr, "Testvector #%i of %s passed!\n", which, what);
73 | #endif
74 | }
75 | #else
76 | LTC_UNUSED_PARAM(which);
77 | LTC_UNUSED_PARAM(what);
78 | #endif
79 |
80 | return res;
81 | }
82 |
--------------------------------------------------------------------------------
/convert.go:
--------------------------------------------------------------------------------
1 | // Extracted from Go database/sql source code
2 |
3 | // Copyright 2011 The Go Authors. All rights reserved.
4 | // Use of this source code is governed by a BSD-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // Type conversions for Scan.
8 |
9 | package sqlite3
10 |
11 | import (
12 | "database/sql"
13 | "database/sql/driver"
14 | "errors"
15 | "fmt"
16 | "reflect"
17 | "strconv"
18 | "time"
19 | )
20 |
21 | var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
22 |
23 | // convertAssign copies to dest the value in src, converting it if possible.
24 | // An error is returned if the copy would result in loss of information.
25 | // dest should be a pointer type.
26 | func convertAssign(dest, src interface{}) error {
27 | // Common cases, without reflect.
28 | switch s := src.(type) {
29 | case string:
30 | switch d := dest.(type) {
31 | case *string:
32 | if d == nil {
33 | return errNilPtr
34 | }
35 | *d = s
36 | return nil
37 | case *[]byte:
38 | if d == nil {
39 | return errNilPtr
40 | }
41 | *d = []byte(s)
42 | return nil
43 | case *sql.RawBytes:
44 | if d == nil {
45 | return errNilPtr
46 | }
47 | *d = append((*d)[:0], s...)
48 | return nil
49 | }
50 | case []byte:
51 | switch d := dest.(type) {
52 | case *string:
53 | if d == nil {
54 | return errNilPtr
55 | }
56 | *d = string(s)
57 | return nil
58 | case *interface{}:
59 | if d == nil {
60 | return errNilPtr
61 | }
62 | *d = cloneBytes(s)
63 | return nil
64 | case *[]byte:
65 | if d == nil {
66 | return errNilPtr
67 | }
68 | *d = cloneBytes(s)
69 | return nil
70 | case *sql.RawBytes:
71 | if d == nil {
72 | return errNilPtr
73 | }
74 | *d = s
75 | return nil
76 | }
77 | case time.Time:
78 | switch d := dest.(type) {
79 | case *time.Time:
80 | *d = s
81 | return nil
82 | case *string:
83 | *d = s.Format(time.RFC3339Nano)
84 | return nil
85 | case *[]byte:
86 | if d == nil {
87 | return errNilPtr
88 | }
89 | *d = []byte(s.Format(time.RFC3339Nano))
90 | return nil
91 | case *sql.RawBytes:
92 | if d == nil {
93 | return errNilPtr
94 | }
95 | *d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
96 | return nil
97 | }
98 | case nil:
99 | switch d := dest.(type) {
100 | case *interface{}:
101 | if d == nil {
102 | return errNilPtr
103 | }
104 | *d = nil
105 | return nil
106 | case *[]byte:
107 | if d == nil {
108 | return errNilPtr
109 | }
110 | *d = nil
111 | return nil
112 | case *sql.RawBytes:
113 | if d == nil {
114 | return errNilPtr
115 | }
116 | *d = nil
117 | return nil
118 | }
119 | }
120 |
121 | var sv reflect.Value
122 |
123 | switch d := dest.(type) {
124 | case *string:
125 | sv = reflect.ValueOf(src)
126 | switch sv.Kind() {
127 | case reflect.Bool,
128 | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
129 | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
130 | reflect.Float32, reflect.Float64:
131 | *d = asString(src)
132 | return nil
133 | }
134 | case *[]byte:
135 | sv = reflect.ValueOf(src)
136 | if b, ok := asBytes(nil, sv); ok {
137 | *d = b
138 | return nil
139 | }
140 | case *sql.RawBytes:
141 | sv = reflect.ValueOf(src)
142 | if b, ok := asBytes([]byte(*d)[:0], sv); ok {
143 | *d = sql.RawBytes(b)
144 | return nil
145 | }
146 | case *bool:
147 | bv, err := driver.Bool.ConvertValue(src)
148 | if err == nil {
149 | *d = bv.(bool)
150 | }
151 | return err
152 | case *interface{}:
153 | *d = src
154 | return nil
155 | }
156 |
157 | if scanner, ok := dest.(sql.Scanner); ok {
158 | return scanner.Scan(src)
159 | }
160 |
161 | dpv := reflect.ValueOf(dest)
162 | if dpv.Kind() != reflect.Ptr {
163 | return errors.New("destination not a pointer")
164 | }
165 | if dpv.IsNil() {
166 | return errNilPtr
167 | }
168 |
169 | if !sv.IsValid() {
170 | sv = reflect.ValueOf(src)
171 | }
172 |
173 | dv := reflect.Indirect(dpv)
174 | if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
175 | switch b := src.(type) {
176 | case []byte:
177 | dv.Set(reflect.ValueOf(cloneBytes(b)))
178 | default:
179 | dv.Set(sv)
180 | }
181 | return nil
182 | }
183 |
184 | if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
185 | dv.Set(sv.Convert(dv.Type()))
186 | return nil
187 | }
188 |
189 | // The following conversions use a string value as an intermediate representation
190 | // to convert between various numeric types.
191 | //
192 | // This also allows scanning into user defined types such as "type Int int64".
193 | // For symmetry, also check for string destination types.
194 | switch dv.Kind() {
195 | case reflect.Ptr:
196 | if src == nil {
197 | dv.Set(reflect.Zero(dv.Type()))
198 | return nil
199 | }
200 | dv.Set(reflect.New(dv.Type().Elem()))
201 | return convertAssign(dv.Interface(), src)
202 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
203 | s := asString(src)
204 | i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
205 | if err != nil {
206 | err = strconvErr(err)
207 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
208 | }
209 | dv.SetInt(i64)
210 | return nil
211 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
212 | s := asString(src)
213 | u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
214 | if err != nil {
215 | err = strconvErr(err)
216 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
217 | }
218 | dv.SetUint(u64)
219 | return nil
220 | case reflect.Float32, reflect.Float64:
221 | s := asString(src)
222 | f64, err := strconv.ParseFloat(s, dv.Type().Bits())
223 | if err != nil {
224 | err = strconvErr(err)
225 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
226 | }
227 | dv.SetFloat(f64)
228 | return nil
229 | case reflect.String:
230 | switch v := src.(type) {
231 | case string:
232 | dv.SetString(v)
233 | return nil
234 | case []byte:
235 | dv.SetString(string(v))
236 | return nil
237 | }
238 | }
239 |
240 | return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
241 | }
242 |
243 | func strconvErr(err error) error {
244 | if ne, ok := err.(*strconv.NumError); ok {
245 | return ne.Err
246 | }
247 | return err
248 | }
249 |
250 | func cloneBytes(b []byte) []byte {
251 | if b == nil {
252 | return nil
253 | }
254 | c := make([]byte, len(b))
255 | copy(c, b)
256 | return c
257 | }
258 |
259 | func asString(src interface{}) string {
260 | switch v := src.(type) {
261 | case string:
262 | return v
263 | case []byte:
264 | return string(v)
265 | }
266 | rv := reflect.ValueOf(src)
267 | switch rv.Kind() {
268 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
269 | return strconv.FormatInt(rv.Int(), 10)
270 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
271 | return strconv.FormatUint(rv.Uint(), 10)
272 | case reflect.Float64:
273 | return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
274 | case reflect.Float32:
275 | return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
276 | case reflect.Bool:
277 | return strconv.FormatBool(rv.Bool())
278 | }
279 | return fmt.Sprintf("%v", src)
280 | }
281 |
282 | func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
283 | switch rv.Kind() {
284 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
285 | return strconv.AppendInt(buf, rv.Int(), 10), true
286 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
287 | return strconv.AppendUint(buf, rv.Uint(), 10), true
288 | case reflect.Float32:
289 | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
290 | case reflect.Float64:
291 | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
292 | case reflect.Bool:
293 | return strconv.AppendBool(buf, rv.Bool()), true
294 | case reflect.String:
295 | s := rv.String()
296 | return append(buf, s...), true
297 | }
298 | return
299 | }
300 |
--------------------------------------------------------------------------------
/crypt_argchk.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_argchk.c
7 | Perform argument checking, Tom St Denis
8 | */
9 |
10 | #if (ARGTYPE == 0)
11 | void crypt_argchk(const char *v, const char *s, int d)
12 | {
13 | fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
14 | v, d, s);
15 | abort();
16 | }
17 | #endif
18 |
--------------------------------------------------------------------------------
/crypt_cipher_descriptor.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_cipher_descriptor.c
7 | Stores the cipher descriptor table, Tom St Denis
8 | */
9 |
10 | struct ltc_cipher_descriptor cipher_descriptor[TAB_SIZE] = {
11 | { NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
12 | };
13 |
14 | LTC_MUTEX_GLOBAL(ltc_cipher_mutex)
15 |
16 |
--------------------------------------------------------------------------------
/crypt_cipher_is_valid.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_cipher_is_valid.c
7 | Determine if cipher is valid, Tom St Denis
8 | */
9 |
10 | /*
11 | Test if a cipher index is valid
12 | @param idx The index of the cipher to search for
13 | @return CRYPT_OK if valid
14 | */
15 | int cipher_is_valid(int idx)
16 | {
17 | LTC_MUTEX_LOCK(<c_cipher_mutex);
18 | if (idx < 0 || idx >= TAB_SIZE || cipher_descriptor[idx].name == NULL) {
19 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
20 | return CRYPT_INVALID_CIPHER;
21 | }
22 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
23 | return CRYPT_OK;
24 | }
25 |
--------------------------------------------------------------------------------
/crypt_find_cipher.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_find_cipher.c
7 | Find a cipher in the descriptor tables, Tom St Denis
8 | */
9 |
10 | /**
11 | Find a registered cipher by name
12 | @param name The name of the cipher to look for
13 | @return >= 0 if found, -1 if not present
14 | */
15 | int find_cipher(const char *name)
16 | {
17 | int x;
18 | LTC_ARGCHK(name != NULL);
19 | LTC_MUTEX_LOCK(<c_cipher_mutex);
20 | for (x = 0; x < TAB_SIZE; x++) {
21 | if (cipher_descriptor[x].name != NULL && !XSTRCMP(cipher_descriptor[x].name, name)) {
22 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
23 | return x;
24 | }
25 | }
26 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
27 | return -1;
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/crypt_find_hash.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_find_hash.c
7 | Find a hash, Tom St Denis
8 | */
9 |
10 | /**
11 | Find a registered hash by name
12 | @param name The name of the hash to look for
13 | @return >= 0 if found, -1 if not present
14 | */
15 | int find_hash(const char *name)
16 | {
17 | int x;
18 | LTC_ARGCHK(name != NULL);
19 | LTC_MUTEX_LOCK(<c_hash_mutex);
20 | for (x = 0; x < TAB_SIZE; x++) {
21 | if (hash_descriptor[x].name != NULL && XSTRCMP(hash_descriptor[x].name, name) == 0) {
22 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
23 | return x;
24 | }
25 | }
26 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
27 | return -1;
28 | }
29 |
--------------------------------------------------------------------------------
/crypt_hash_descriptor.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_hash_descriptor.c
7 | Stores the hash descriptor table, Tom St Denis
8 | */
9 |
10 | struct ltc_hash_descriptor hash_descriptor[TAB_SIZE] = {
11 | { NULL, 0, 0, 0, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }
12 | };
13 |
14 | LTC_MUTEX_GLOBAL(ltc_hash_mutex)
15 |
16 |
--------------------------------------------------------------------------------
/crypt_hash_is_valid.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_hash_is_valid.c
7 | Determine if hash is valid, Tom St Denis
8 | */
9 |
10 | /*
11 | Test if a hash index is valid
12 | @param idx The index of the hash to search for
13 | @return CRYPT_OK if valid
14 | */
15 | int hash_is_valid(int idx)
16 | {
17 | LTC_MUTEX_LOCK(<c_hash_mutex);
18 | if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
19 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
20 | return CRYPT_INVALID_HASH;
21 | }
22 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
23 | return CRYPT_OK;
24 | }
25 |
--------------------------------------------------------------------------------
/crypt_prng_descriptor.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_prng_descriptor.c
7 | Stores the PRNG descriptors, Tom St Denis
8 | */
9 | struct ltc_prng_descriptor prng_descriptor[TAB_SIZE] = {
10 | { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
11 | };
12 |
13 | LTC_MUTEX_GLOBAL(ltc_prng_mutex)
14 |
15 |
--------------------------------------------------------------------------------
/crypt_register_cipher.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_register_cipher.c
7 | Register a cipher, Tom St Denis
8 | */
9 |
10 | /**
11 | Register a cipher with the descriptor table
12 | @param cipher The cipher you wish to register
13 | @return value >= 0 if successfully added (or already present), -1 if unsuccessful
14 | */
15 | int register_cipher(const struct ltc_cipher_descriptor *cipher)
16 | {
17 | int x;
18 |
19 | LTC_ARGCHK(cipher != NULL);
20 |
21 | /* is it already registered? */
22 | LTC_MUTEX_LOCK(<c_cipher_mutex);
23 | for (x = 0; x < TAB_SIZE; x++) {
24 | if (cipher_descriptor[x].name != NULL && cipher_descriptor[x].ID == cipher->ID) {
25 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
26 | return x;
27 | }
28 | }
29 |
30 | /* find a blank spot */
31 | for (x = 0; x < TAB_SIZE; x++) {
32 | if (cipher_descriptor[x].name == NULL) {
33 | XMEMCPY(&cipher_descriptor[x], cipher, sizeof(struct ltc_cipher_descriptor));
34 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
35 | return x;
36 | }
37 | }
38 |
39 | /* no spot */
40 | LTC_MUTEX_UNLOCK(<c_cipher_mutex);
41 | return -1;
42 | }
43 |
--------------------------------------------------------------------------------
/crypt_register_hash.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_register_hash.c
7 | Register a HASH, Tom St Denis
8 | */
9 |
10 | /**
11 | Register a hash with the descriptor table
12 | @param hash The hash you wish to register
13 | @return value >= 0 if successfully added (or already present), -1 if unsuccessful
14 | */
15 | int register_hash(const struct ltc_hash_descriptor *hash)
16 | {
17 | int x;
18 |
19 | LTC_ARGCHK(hash != NULL);
20 |
21 | /* is it already registered? */
22 | LTC_MUTEX_LOCK(<c_hash_mutex);
23 | for (x = 0; x < TAB_SIZE; x++) {
24 | if (XMEMCMP(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor)) == 0) {
25 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
26 | return x;
27 | }
28 | }
29 |
30 | /* find a blank spot */
31 | for (x = 0; x < TAB_SIZE; x++) {
32 | if (hash_descriptor[x].name == NULL) {
33 | XMEMCPY(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor));
34 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
35 | return x;
36 | }
37 | }
38 |
39 | /* no spot */
40 | LTC_MUTEX_UNLOCK(<c_hash_mutex);
41 | return -1;
42 | }
43 |
--------------------------------------------------------------------------------
/crypt_register_prng.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file crypt_register_prng.c
7 | Register a PRNG, Tom St Denis
8 | */
9 |
10 | /**
11 | Register a PRNG with the descriptor table
12 | @param prng The PRNG you wish to register
13 | @return value >= 0 if successfully added (or already present), -1 if unsuccessful
14 | */
15 | int register_prng(const struct ltc_prng_descriptor *prng)
16 | {
17 | int x;
18 |
19 | LTC_ARGCHK(prng != NULL);
20 |
21 | /* is it already registered? */
22 | LTC_MUTEX_LOCK(<c_prng_mutex);
23 | for (x = 0; x < TAB_SIZE; x++) {
24 | if (XMEMCMP(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor)) == 0) {
25 | LTC_MUTEX_UNLOCK(<c_prng_mutex);
26 | return x;
27 | }
28 | }
29 |
30 | /* find a blank spot */
31 | for (x = 0; x < TAB_SIZE; x++) {
32 | if (prng_descriptor[x].name == NULL) {
33 | XMEMCPY(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor));
34 | LTC_MUTEX_UNLOCK(<c_prng_mutex);
35 | return x;
36 | }
37 | }
38 |
39 | /* no spot */
40 | LTC_MUTEX_UNLOCK(<c_prng_mutex);
41 | return -1;
42 | }
43 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package sqlite3 provides interface to SQLite3 databases.
3 |
4 | This works as a driver for database/sql.
5 |
6 | Installation
7 |
8 | go get github.com/mattn/go-sqlite3
9 |
10 | Supported Types
11 |
12 | Currently, go-sqlite3 supports the following data types.
13 |
14 | +------------------------------+
15 | |go | sqlite3 |
16 | |----------|-------------------|
17 | |nil | null |
18 | |int | integer |
19 | |int64 | integer |
20 | |float64 | float |
21 | |bool | integer |
22 | |[]byte | blob |
23 | |string | text |
24 | |time.Time | timestamp/datetime|
25 | +------------------------------+
26 |
27 | SQLite3 Extension
28 |
29 | You can write your own extension module for sqlite3. For example, below is an
30 | extension for a Regexp matcher operation.
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | SQLITE_EXTENSION_INIT1
38 | static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
39 | if (argc >= 2) {
40 | const char *target = (const char *)sqlite3_value_text(argv[1]);
41 | const char *pattern = (const char *)sqlite3_value_text(argv[0]);
42 | const char* errstr = NULL;
43 | int erroff = 0;
44 | int vec[500];
45 | int n, rc;
46 | pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
47 | rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
48 | if (rc <= 0) {
49 | sqlite3_result_error(context, errstr, 0);
50 | return;
51 | }
52 | sqlite3_result_int(context, 1);
53 | }
54 | }
55 |
56 | #ifdef _WIN32
57 | __declspec(dllexport)
58 | #endif
59 | int sqlite3_extension_init(sqlite3 *db, char **errmsg,
60 | const sqlite3_api_routines *api) {
61 | SQLITE_EXTENSION_INIT2(api);
62 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8,
63 | (void*)db, regexp_func, NULL, NULL);
64 | }
65 |
66 | It needs to be built as a so/dll shared library. And you need to register
67 | the extension module like below.
68 |
69 | sql.Register("sqlite3_with_extensions",
70 | &sqlite3.SQLiteDriver{
71 | Extensions: []string{
72 | "sqlite3_mod_regexp",
73 | },
74 | })
75 |
76 | Then, you can use this extension.
77 |
78 | rows, err := db.Query("select text from mytable where name regexp '^golang'")
79 |
80 | Connection Hook
81 |
82 | You can hook and inject your code when the connection is established by setting
83 | ConnectHook to get the SQLiteConn.
84 |
85 | sql.Register("sqlite3_with_hook_example",
86 | &sqlite3.SQLiteDriver{
87 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
88 | sqlite3conn = append(sqlite3conn, conn)
89 | return nil
90 | },
91 | })
92 |
93 | You can also use database/sql.Conn.Raw (Go >= 1.13):
94 |
95 | conn, err := db.Conn(context.Background())
96 | // if err != nil { ... }
97 | defer conn.Close()
98 | err = conn.Raw(func (driverConn interface{}) error {
99 | sqliteConn := driverConn.(*sqlite3.SQLiteConn)
100 | // ... use sqliteConn
101 | })
102 | // if err != nil { ... }
103 |
104 | Go SQlite3 Extensions
105 |
106 | If you want to register Go functions as SQLite extension functions
107 | you can make a custom driver by calling RegisterFunction from
108 | ConnectHook.
109 |
110 | regex = func(re, s string) (bool, error) {
111 | return regexp.MatchString(re, s)
112 | }
113 | sql.Register("sqlite3_extended",
114 | &sqlite3.SQLiteDriver{
115 | ConnectHook: func(conn *sqlite3.SQLiteConn) error {
116 | return conn.RegisterFunc("regexp", regex, true)
117 | },
118 | })
119 |
120 | You can then use the custom driver by passing its name to sql.Open.
121 |
122 | var i int
123 | conn, err := sql.Open("sqlite3_extended", "./foo.db")
124 | if err != nil {
125 | panic(err)
126 | }
127 | err = db.QueryRow(`SELECT regexp("foo.*", "seafood")`).Scan(&i)
128 | if err != nil {
129 | panic(err)
130 | }
131 |
132 | See the documentation of RegisterFunc for more details.
133 |
134 | */
135 | package sqlite3
136 |
--------------------------------------------------------------------------------
/error.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | /*
9 | #ifndef USE_LIBSQLITE3
10 | #include
11 | #else
12 | #include
13 | #endif
14 | */
15 | import "C"
16 | import "syscall"
17 |
18 | // ErrNo inherit errno.
19 | type ErrNo int
20 |
21 | // ErrNoMask is mask code.
22 | const ErrNoMask C.int = 0xff
23 |
24 | // ErrNoExtended is extended errno.
25 | type ErrNoExtended int
26 |
27 | // Error implement sqlite error code.
28 | type Error struct {
29 | Code ErrNo /* The error code returned by SQLite */
30 | ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */
31 | SystemErrno syscall.Errno /* The system errno returned by the OS through SQLite, if applicable */
32 | err string /* The error string returned by sqlite3_errmsg(),
33 | this usually contains more specific details. */
34 | }
35 |
36 | // result codes from http://www.sqlite.org/c3ref/c_abort.html
37 | var (
38 | ErrError = ErrNo(1) /* SQL error or missing database */
39 | ErrInternal = ErrNo(2) /* Internal logic error in SQLite */
40 | ErrPerm = ErrNo(3) /* Access permission denied */
41 | ErrAbort = ErrNo(4) /* Callback routine requested an abort */
42 | ErrBusy = ErrNo(5) /* The database file is locked */
43 | ErrLocked = ErrNo(6) /* A table in the database is locked */
44 | ErrNomem = ErrNo(7) /* A malloc() failed */
45 | ErrReadonly = ErrNo(8) /* Attempt to write a readonly database */
46 | ErrInterrupt = ErrNo(9) /* Operation terminated by sqlite3_interrupt() */
47 | ErrIoErr = ErrNo(10) /* Some kind of disk I/O error occurred */
48 | ErrCorrupt = ErrNo(11) /* The database disk image is malformed */
49 | ErrNotFound = ErrNo(12) /* Unknown opcode in sqlite3_file_control() */
50 | ErrFull = ErrNo(13) /* Insertion failed because database is full */
51 | ErrCantOpen = ErrNo(14) /* Unable to open the database file */
52 | ErrProtocol = ErrNo(15) /* Database lock protocol error */
53 | ErrEmpty = ErrNo(16) /* Database is empty */
54 | ErrSchema = ErrNo(17) /* The database schema changed */
55 | ErrTooBig = ErrNo(18) /* String or BLOB exceeds size limit */
56 | ErrConstraint = ErrNo(19) /* Abort due to constraint violation */
57 | ErrMismatch = ErrNo(20) /* Data type mismatch */
58 | ErrMisuse = ErrNo(21) /* Library used incorrectly */
59 | ErrNoLFS = ErrNo(22) /* Uses OS features not supported on host */
60 | ErrAuth = ErrNo(23) /* Authorization denied */
61 | ErrFormat = ErrNo(24) /* Auxiliary database format error */
62 | ErrRange = ErrNo(25) /* 2nd parameter to sqlite3_bind out of range */
63 | ErrNotADB = ErrNo(26) /* File opened that is not a database file */
64 | ErrNotice = ErrNo(27) /* Notifications from sqlite3_log() */
65 | ErrWarning = ErrNo(28) /* Warnings from sqlite3_log() */
66 | )
67 |
68 | // Error return error message from errno.
69 | func (err ErrNo) Error() string {
70 | return Error{Code: err}.Error()
71 | }
72 |
73 | // Extend return extended errno.
74 | func (err ErrNo) Extend(by int) ErrNoExtended {
75 | return ErrNoExtended(int(err) | (by << 8))
76 | }
77 |
78 | // Error return error message that is extended code.
79 | func (err ErrNoExtended) Error() string {
80 | return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error()
81 | }
82 |
83 | func (err Error) Error() string {
84 | var str string
85 | if err.err != "" {
86 | str = err.err
87 | } else {
88 | str = C.GoString(C.sqlite3_errstr(C.int(err.Code)))
89 | }
90 | if err.SystemErrno != 0 {
91 | str += ": " + err.SystemErrno.Error()
92 | }
93 | return str
94 | }
95 |
96 | // result codes from http://www.sqlite.org/c3ref/c_abort_rollback.html
97 | var (
98 | ErrIoErrRead = ErrIoErr.Extend(1)
99 | ErrIoErrShortRead = ErrIoErr.Extend(2)
100 | ErrIoErrWrite = ErrIoErr.Extend(3)
101 | ErrIoErrFsync = ErrIoErr.Extend(4)
102 | ErrIoErrDirFsync = ErrIoErr.Extend(5)
103 | ErrIoErrTruncate = ErrIoErr.Extend(6)
104 | ErrIoErrFstat = ErrIoErr.Extend(7)
105 | ErrIoErrUnlock = ErrIoErr.Extend(8)
106 | ErrIoErrRDlock = ErrIoErr.Extend(9)
107 | ErrIoErrDelete = ErrIoErr.Extend(10)
108 | ErrIoErrBlocked = ErrIoErr.Extend(11)
109 | ErrIoErrNoMem = ErrIoErr.Extend(12)
110 | ErrIoErrAccess = ErrIoErr.Extend(13)
111 | ErrIoErrCheckReservedLock = ErrIoErr.Extend(14)
112 | ErrIoErrLock = ErrIoErr.Extend(15)
113 | ErrIoErrClose = ErrIoErr.Extend(16)
114 | ErrIoErrDirClose = ErrIoErr.Extend(17)
115 | ErrIoErrSHMOpen = ErrIoErr.Extend(18)
116 | ErrIoErrSHMSize = ErrIoErr.Extend(19)
117 | ErrIoErrSHMLock = ErrIoErr.Extend(20)
118 | ErrIoErrSHMMap = ErrIoErr.Extend(21)
119 | ErrIoErrSeek = ErrIoErr.Extend(22)
120 | ErrIoErrDeleteNoent = ErrIoErr.Extend(23)
121 | ErrIoErrMMap = ErrIoErr.Extend(24)
122 | ErrIoErrGetTempPath = ErrIoErr.Extend(25)
123 | ErrIoErrConvPath = ErrIoErr.Extend(26)
124 | ErrLockedSharedCache = ErrLocked.Extend(1)
125 | ErrBusyRecovery = ErrBusy.Extend(1)
126 | ErrBusySnapshot = ErrBusy.Extend(2)
127 | ErrCantOpenNoTempDir = ErrCantOpen.Extend(1)
128 | ErrCantOpenIsDir = ErrCantOpen.Extend(2)
129 | ErrCantOpenFullPath = ErrCantOpen.Extend(3)
130 | ErrCantOpenConvPath = ErrCantOpen.Extend(4)
131 | ErrCorruptVTab = ErrCorrupt.Extend(1)
132 | ErrReadonlyRecovery = ErrReadonly.Extend(1)
133 | ErrReadonlyCantLock = ErrReadonly.Extend(2)
134 | ErrReadonlyRollback = ErrReadonly.Extend(3)
135 | ErrReadonlyDbMoved = ErrReadonly.Extend(4)
136 | ErrAbortRollback = ErrAbort.Extend(2)
137 | ErrConstraintCheck = ErrConstraint.Extend(1)
138 | ErrConstraintCommitHook = ErrConstraint.Extend(2)
139 | ErrConstraintForeignKey = ErrConstraint.Extend(3)
140 | ErrConstraintFunction = ErrConstraint.Extend(4)
141 | ErrConstraintNotNull = ErrConstraint.Extend(5)
142 | ErrConstraintPrimaryKey = ErrConstraint.Extend(6)
143 | ErrConstraintTrigger = ErrConstraint.Extend(7)
144 | ErrConstraintUnique = ErrConstraint.Extend(8)
145 | ErrConstraintVTab = ErrConstraint.Extend(9)
146 | ErrConstraintRowID = ErrConstraint.Extend(10)
147 | ErrNoticeRecoverWAL = ErrNotice.Extend(1)
148 | ErrNoticeRecoverRollback = ErrNotice.Extend(2)
149 | ErrWarningAutoIndex = ErrWarning.Extend(1)
150 | )
151 |
--------------------------------------------------------------------------------
/error_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 |
8 | package sqlite3
9 |
10 | import (
11 | "database/sql"
12 | "io/ioutil"
13 | "os"
14 | "path"
15 | "testing"
16 | )
17 |
18 | func TestSimpleError(t *testing.T) {
19 | e := ErrError.Error()
20 | if e != "SQL logic error or missing database" && e != "SQL logic error" {
21 | t.Error("wrong error code: " + e)
22 | }
23 | }
24 |
25 | func TestCorruptDbErrors(t *testing.T) {
26 | dirName, err := ioutil.TempDir("", "sqlite3")
27 | if err != nil {
28 | t.Fatal(err)
29 | }
30 | defer os.RemoveAll(dirName)
31 |
32 | dbFileName := path.Join(dirName, "test.db")
33 | f, err := os.Create(dbFileName)
34 | if err != nil {
35 | t.Error(err)
36 | }
37 | f.Write([]byte{1, 2, 3, 4, 5})
38 | f.Close()
39 |
40 | db, err := sql.Open("sqlite3", dbFileName)
41 | if err == nil {
42 | _, err = db.Exec("drop table foo")
43 | }
44 |
45 | sqliteErr := err.(Error)
46 | if sqliteErr.Code != ErrNotADB {
47 | t.Error("wrong error code for corrupted DB")
48 | }
49 | if err.Error() == "" {
50 | t.Error("wrong error string for corrupted DB")
51 | }
52 | db.Close()
53 | }
54 |
55 | func TestSqlLogicErrors(t *testing.T) {
56 | dirName, err := ioutil.TempDir("", "sqlite3")
57 | if err != nil {
58 | t.Fatal(err)
59 | }
60 | defer os.RemoveAll(dirName)
61 |
62 | dbFileName := path.Join(dirName, "test.db")
63 | db, err := sql.Open("sqlite3", dbFileName)
64 | if err != nil {
65 | t.Error(err)
66 | }
67 | defer db.Close()
68 |
69 | _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
70 | if err != nil {
71 | t.Error(err)
72 | }
73 |
74 | const expectedErr = "table Foo already exists"
75 | _, err = db.Exec("CREATE TABLE Foo (id INTEGER PRIMARY KEY)")
76 | if err.Error() != expectedErr {
77 | t.Errorf("Unexpected error: %s, expected %s", err.Error(), expectedErr)
78 | }
79 |
80 | }
81 |
82 | func TestExtendedErrorCodes_ForeignKey(t *testing.T) {
83 | dirName, err := ioutil.TempDir("", "sqlite3-err")
84 | if err != nil {
85 | t.Fatal(err)
86 | }
87 | defer os.RemoveAll(dirName)
88 |
89 | dbFileName := path.Join(dirName, "test.db")
90 | db, err := sql.Open("sqlite3", dbFileName)
91 | if err != nil {
92 | t.Error(err)
93 | }
94 | defer db.Close()
95 |
96 | _, err = db.Exec("PRAGMA foreign_keys=ON;")
97 | if err != nil {
98 | t.Errorf("PRAGMA foreign_keys=ON: %v", err)
99 | }
100 |
101 | _, err = db.Exec(`CREATE TABLE Foo (
102 | id INTEGER PRIMARY KEY AUTOINCREMENT,
103 | value INTEGER NOT NULL,
104 | ref INTEGER NULL REFERENCES Foo (id),
105 | UNIQUE(value)
106 | );`)
107 | if err != nil {
108 | t.Error(err)
109 | }
110 |
111 | _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (100, 100);")
112 | if err == nil {
113 | t.Error("No error!")
114 | } else {
115 | sqliteErr := err.(Error)
116 | if sqliteErr.Code != ErrConstraint {
117 | t.Errorf("Wrong basic error code: %d != %d",
118 | sqliteErr.Code, ErrConstraint)
119 | }
120 | if sqliteErr.ExtendedCode != ErrConstraintForeignKey {
121 | t.Errorf("Wrong extended error code: %d != %d",
122 | sqliteErr.ExtendedCode, ErrConstraintForeignKey)
123 | }
124 | }
125 |
126 | }
127 |
128 | func TestExtendedErrorCodes_NotNull(t *testing.T) {
129 | dirName, err := ioutil.TempDir("", "sqlite3-err")
130 | if err != nil {
131 | t.Fatal(err)
132 | }
133 | defer os.RemoveAll(dirName)
134 |
135 | dbFileName := path.Join(dirName, "test.db")
136 | db, err := sql.Open("sqlite3", dbFileName)
137 | if err != nil {
138 | t.Error(err)
139 | }
140 | defer db.Close()
141 |
142 | _, err = db.Exec("PRAGMA foreign_keys=ON;")
143 | if err != nil {
144 | t.Errorf("PRAGMA foreign_keys=ON: %v", err)
145 | }
146 |
147 | _, err = db.Exec(`CREATE TABLE Foo (
148 | id INTEGER PRIMARY KEY AUTOINCREMENT,
149 | value INTEGER NOT NULL,
150 | ref INTEGER NULL REFERENCES Foo (id),
151 | UNIQUE(value)
152 | );`)
153 | if err != nil {
154 | t.Error(err)
155 | }
156 |
157 | res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
158 | if err != nil {
159 | t.Fatalf("Creating first row: %v", err)
160 | }
161 |
162 | id, err := res.LastInsertId()
163 | if err != nil {
164 | t.Fatalf("Retrieving last insert id: %v", err)
165 | }
166 |
167 | _, err = db.Exec("INSERT INTO Foo (ref) VALUES (?);", id)
168 | if err == nil {
169 | t.Error("No error!")
170 | } else {
171 | sqliteErr := err.(Error)
172 | if sqliteErr.Code != ErrConstraint {
173 | t.Errorf("Wrong basic error code: %d != %d",
174 | sqliteErr.Code, ErrConstraint)
175 | }
176 | if sqliteErr.ExtendedCode != ErrConstraintNotNull {
177 | t.Errorf("Wrong extended error code: %d != %d",
178 | sqliteErr.ExtendedCode, ErrConstraintNotNull)
179 | }
180 | }
181 |
182 | }
183 |
184 | func TestExtendedErrorCodes_Unique(t *testing.T) {
185 | dirName, err := ioutil.TempDir("", "sqlite3-err")
186 | if err != nil {
187 | t.Fatal(err)
188 | }
189 | defer os.RemoveAll(dirName)
190 |
191 | dbFileName := path.Join(dirName, "test.db")
192 | db, err := sql.Open("sqlite3", dbFileName)
193 | if err != nil {
194 | t.Error(err)
195 | }
196 | defer db.Close()
197 |
198 | _, err = db.Exec("PRAGMA foreign_keys=ON;")
199 | if err != nil {
200 | t.Errorf("PRAGMA foreign_keys=ON: %v", err)
201 | }
202 |
203 | _, err = db.Exec(`CREATE TABLE Foo (
204 | id INTEGER PRIMARY KEY AUTOINCREMENT,
205 | value INTEGER NOT NULL,
206 | ref INTEGER NULL REFERENCES Foo (id),
207 | UNIQUE(value)
208 | );`)
209 | if err != nil {
210 | t.Error(err)
211 | }
212 |
213 | res, err := db.Exec("INSERT INTO Foo (value) VALUES (100);")
214 | if err != nil {
215 | t.Fatalf("Creating first row: %v", err)
216 | }
217 |
218 | id, err := res.LastInsertId()
219 | if err != nil {
220 | t.Fatalf("Retrieving last insert id: %v", err)
221 | }
222 |
223 | _, err = db.Exec("INSERT INTO Foo (ref, value) VALUES (?, 100);", id)
224 | if err == nil {
225 | t.Error("No error!")
226 | } else {
227 | sqliteErr := err.(Error)
228 | if sqliteErr.Code != ErrConstraint {
229 | t.Errorf("Wrong basic error code: %d != %d",
230 | sqliteErr.Code, ErrConstraint)
231 | }
232 | if sqliteErr.ExtendedCode != ErrConstraintUnique {
233 | t.Errorf("Wrong extended error code: %d != %d",
234 | sqliteErr.ExtendedCode, ErrConstraintUnique)
235 | }
236 | extended := sqliteErr.Code.Extend(3).Error()
237 | expected := "constraint failed"
238 | if extended != expected {
239 | t.Errorf("Wrong basic error code: %q != %q",
240 | extended, expected)
241 | }
242 | }
243 | }
244 |
245 | func TestError_SystemErrno(t *testing.T) {
246 | _, n, _ := Version()
247 | if n < 3012000 {
248 | t.Skip("sqlite3_system_errno requires sqlite3 >= 3.12.0")
249 | }
250 |
251 | // open a non-existent database in read-only mode so we get an IO error.
252 | db, err := sql.Open("sqlite3", "file:nonexistent.db?mode=ro")
253 | if err != nil {
254 | t.Fatal(err)
255 | }
256 | defer db.Close()
257 |
258 | err = db.Ping()
259 | if err == nil {
260 | t.Fatal("expected error pinging read-only non-existent database, but got nil")
261 | }
262 |
263 | serr, ok := err.(Error)
264 | if !ok {
265 | t.Fatalf("expected error to be of type Error, but got %[1]T %[1]v", err)
266 | }
267 |
268 | if serr.SystemErrno == 0 {
269 | t.Fatal("expected SystemErrno to be set")
270 | }
271 |
272 | if !os.IsNotExist(serr.SystemErrno) {
273 | t.Errorf("expected SystemErrno to be a not exists error, but got %v", serr.SystemErrno)
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/flags.go:
--------------------------------------------------------------------------------
1 | package sqlite3
2 |
3 | /*
4 | // make go-sqlite3 use embedded library without code changes
5 | #cgo CFLAGS: -DUSE_LIBSQLITE3
6 |
7 | // enable encryption codec in sqlite
8 | #cgo CFLAGS: -DSQLITE_HAS_CODEC
9 |
10 | // use memory for temporay storage in sqlite
11 | #cgo CFLAGS: -DSQLITE_TEMP_STORE=2
12 |
13 | // use libtomcrypt implementation in sqlcipher
14 | #cgo CFLAGS: -DSQLCIPHER_CRYPTO_LIBTOMCRYPT
15 |
16 | // disable anything "not portable" in libtomcrypt
17 | #cgo CFLAGS: -DLTC_NO_ASM
18 |
19 | // disable assertions
20 | #cgo CFLAGS: -DNDEBUG
21 |
22 | // set operating specific sqlite flags
23 | #cgo linux CFLAGS: -DSQLITE_OS_UNIX=1
24 | #cgo windows CFLAGS: -DSQLITE_OS_WIN=1
25 | */
26 | import "C"
27 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/mutecomm/go-sqlcipher/v4
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1 // indirect
7 | github.com/stretchr/testify v1.3.0
8 | )
9 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
8 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
9 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
10 |
--------------------------------------------------------------------------------
/hash_memory.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | #ifdef LTC_HASH_HELPERS
6 | /**
7 | @file hash_memory.c
8 | Hash memory helper, Tom St Denis
9 | */
10 |
11 | /**
12 | Hash a block of memory and store the digest.
13 | @param hash The index of the hash you wish to use
14 | @param in The data you wish to hash
15 | @param inlen The length of the data to hash (octets)
16 | @param out [out] Where to store the digest
17 | @param outlen [in/out] Max size and resulting size of the digest
18 | @return CRYPT_OK if successful
19 | */
20 | int hash_memory(int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
21 | {
22 | hash_state *md;
23 | int err;
24 |
25 | LTC_ARGCHK(in != NULL);
26 | LTC_ARGCHK(out != NULL);
27 | LTC_ARGCHK(outlen != NULL);
28 |
29 | if ((err = hash_is_valid(hash)) != CRYPT_OK) {
30 | return err;
31 | }
32 |
33 | if (*outlen < hash_descriptor[hash].hashsize) {
34 | *outlen = hash_descriptor[hash].hashsize;
35 | return CRYPT_BUFFER_OVERFLOW;
36 | }
37 |
38 | md = XMALLOC(sizeof(hash_state));
39 | if (md == NULL) {
40 | return CRYPT_MEM;
41 | }
42 |
43 | if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
44 | goto LBL_ERR;
45 | }
46 | if ((err = hash_descriptor[hash].process(md, in, inlen)) != CRYPT_OK) {
47 | goto LBL_ERR;
48 | }
49 | err = hash_descriptor[hash].done(md, out);
50 | *outlen = hash_descriptor[hash].hashsize;
51 | LBL_ERR:
52 | #ifdef LTC_CLEAN_STACK
53 | zeromem(md, sizeof(hash_state));
54 | #endif
55 | XFREE(md);
56 |
57 | return err;
58 | }
59 | #endif /* #ifdef LTC_HASH_HELPERS */
60 |
--------------------------------------------------------------------------------
/hmac_done.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file hmac_done.c
7 | HMAC support, terminate stream, Tom St Denis/Dobes Vandermeer
8 | */
9 |
10 | #ifdef LTC_HMAC
11 |
12 | #define LTC_HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
13 |
14 | /**
15 | Terminate an HMAC session
16 | @param hmac The HMAC state
17 | @param out [out] The destination of the HMAC authentication tag
18 | @param outlen [in/out] The max size and resulting size of the HMAC authentication tag
19 | @return CRYPT_OK if successful
20 | */
21 | int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
22 | {
23 | unsigned char *buf, *isha;
24 | unsigned long hashsize, i;
25 | int hash, err;
26 |
27 | LTC_ARGCHK(hmac != NULL);
28 | LTC_ARGCHK(out != NULL);
29 |
30 | /* test hash */
31 | hash = hmac->hash;
32 | if((err = hash_is_valid(hash)) != CRYPT_OK) {
33 | return err;
34 | }
35 |
36 | /* get the hash message digest size */
37 | hashsize = hash_descriptor[hash].hashsize;
38 |
39 | /* allocate buffers */
40 | buf = XMALLOC(LTC_HMAC_BLOCKSIZE);
41 | isha = XMALLOC(hashsize);
42 | if (buf == NULL || isha == NULL) {
43 | if (buf != NULL) {
44 | XFREE(buf);
45 | }
46 | if (isha != NULL) {
47 | XFREE(isha);
48 | }
49 | return CRYPT_MEM;
50 | }
51 |
52 | /* Get the hash of the first HMAC vector plus the data */
53 | if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
54 | goto LBL_ERR;
55 | }
56 |
57 | /* Create the second HMAC vector vector for step (3) */
58 | for(i=0; i < LTC_HMAC_BLOCKSIZE; i++) {
59 | buf[i] = hmac->key[i] ^ 0x5C;
60 | }
61 |
62 | /* Now calculate the "outer" hash for step (5), (6), and (7) */
63 | if ((err = hash_descriptor[hash].init(&hmac->md)) != CRYPT_OK) {
64 | goto LBL_ERR;
65 | }
66 | if ((err = hash_descriptor[hash].process(&hmac->md, buf, LTC_HMAC_BLOCKSIZE)) != CRYPT_OK) {
67 | goto LBL_ERR;
68 | }
69 | if ((err = hash_descriptor[hash].process(&hmac->md, isha, hashsize)) != CRYPT_OK) {
70 | goto LBL_ERR;
71 | }
72 | if ((err = hash_descriptor[hash].done(&hmac->md, buf)) != CRYPT_OK) {
73 | goto LBL_ERR;
74 | }
75 |
76 | /* copy to output */
77 | for (i = 0; i < hashsize && i < *outlen; i++) {
78 | out[i] = buf[i];
79 | }
80 | *outlen = i;
81 |
82 | err = CRYPT_OK;
83 | LBL_ERR:
84 | #ifdef LTC_CLEAN_STACK
85 | zeromem(isha, hashsize);
86 | zeromem(buf, hashsize);
87 | zeromem(hmac, sizeof(*hmac));
88 | #endif
89 |
90 | XFREE(isha);
91 | XFREE(buf);
92 |
93 | return err;
94 | }
95 |
96 | #endif
97 |
--------------------------------------------------------------------------------
/hmac_init.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file hmac_init.c
7 | HMAC support, initialize state, Tom St Denis/Dobes Vandermeer
8 | */
9 |
10 | #ifdef LTC_HMAC
11 |
12 | #define LTC_HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
13 |
14 | /**
15 | Initialize an HMAC context.
16 | @param hmac The HMAC state
17 | @param hash The index of the hash you want to use
18 | @param key The secret key
19 | @param keylen The length of the secret key (octets)
20 | @return CRYPT_OK if successful
21 | */
22 | int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
23 | {
24 | unsigned char *buf;
25 | unsigned long hashsize;
26 | unsigned long i, z;
27 | int err;
28 |
29 | LTC_ARGCHK(hmac != NULL);
30 | LTC_ARGCHK(key != NULL);
31 |
32 | /* valid hash? */
33 | if ((err = hash_is_valid(hash)) != CRYPT_OK) {
34 | return err;
35 | }
36 | hmac->hash = hash;
37 | hashsize = hash_descriptor[hash].hashsize;
38 |
39 | /* valid key length? */
40 | if (keylen == 0) {
41 | return CRYPT_INVALID_KEYSIZE;
42 | }
43 |
44 | /* allocate ram for buf */
45 | buf = XMALLOC(LTC_HMAC_BLOCKSIZE);
46 | if (buf == NULL) {
47 | return CRYPT_MEM;
48 | }
49 |
50 | /* check hash block fits */
51 | if (sizeof(hmac->key) < LTC_HMAC_BLOCKSIZE) {
52 | err = CRYPT_BUFFER_OVERFLOW;
53 | goto LBL_ERR;
54 | }
55 |
56 | /* (1) make sure we have a large enough key */
57 | if(keylen > LTC_HMAC_BLOCKSIZE) {
58 | z = LTC_HMAC_BLOCKSIZE;
59 | if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
60 | goto LBL_ERR;
61 | }
62 | keylen = hashsize;
63 | } else {
64 | XMEMCPY(hmac->key, key, (size_t)keylen);
65 | }
66 |
67 | if(keylen < LTC_HMAC_BLOCKSIZE) {
68 | zeromem((hmac->key) + keylen, (size_t)(LTC_HMAC_BLOCKSIZE - keylen));
69 | }
70 |
71 | /* Create the initialization vector for step (3) */
72 | for(i=0; i < LTC_HMAC_BLOCKSIZE; i++) {
73 | buf[i] = hmac->key[i] ^ 0x36;
74 | }
75 |
76 | /* Pre-pend that to the hash data */
77 | if ((err = hash_descriptor[hash].init(&hmac->md)) != CRYPT_OK) {
78 | goto LBL_ERR;
79 | }
80 |
81 | if ((err = hash_descriptor[hash].process(&hmac->md, buf, LTC_HMAC_BLOCKSIZE)) != CRYPT_OK) {
82 | goto LBL_ERR;
83 | }
84 |
85 | LBL_ERR:
86 | #ifdef LTC_CLEAN_STACK
87 | zeromem(buf, LTC_HMAC_BLOCKSIZE);
88 | #endif
89 |
90 | XFREE(buf);
91 | return err;
92 | }
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/hmac_memory.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file hmac_memory.c
7 | HMAC support, process a block of memory, Tom St Denis/Dobes Vandermeer
8 | */
9 |
10 | #ifdef LTC_HMAC
11 |
12 | /**
13 | HMAC a block of memory to produce the authentication tag
14 | @param hash The index of the hash to use
15 | @param key The secret key
16 | @param keylen The length of the secret key (octets)
17 | @param in The data to HMAC
18 | @param inlen The length of the data to HMAC (octets)
19 | @param out [out] Destination of the authentication tag
20 | @param outlen [in/out] Max size and resulting size of authentication tag
21 | @return CRYPT_OK if successful
22 | */
23 | int hmac_memory(int hash,
24 | const unsigned char *key, unsigned long keylen,
25 | const unsigned char *in, unsigned long inlen,
26 | unsigned char *out, unsigned long *outlen)
27 | {
28 | hmac_state *hmac;
29 | int err;
30 |
31 | LTC_ARGCHK(key != NULL);
32 | LTC_ARGCHK(in != NULL);
33 | LTC_ARGCHK(out != NULL);
34 | LTC_ARGCHK(outlen != NULL);
35 |
36 | /* make sure hash descriptor is valid */
37 | if ((err = hash_is_valid(hash)) != CRYPT_OK) {
38 | return err;
39 | }
40 |
41 | /* is there a descriptor? */
42 | if (hash_descriptor[hash].hmac_block != NULL) {
43 | return hash_descriptor[hash].hmac_block(key, keylen, in, inlen, out, outlen);
44 | }
45 |
46 | /* nope, so call the hmac functions */
47 | /* allocate ram for hmac state */
48 | hmac = XMALLOC(sizeof(hmac_state));
49 | if (hmac == NULL) {
50 | return CRYPT_MEM;
51 | }
52 |
53 | if ((err = hmac_init(hmac, hash, key, keylen)) != CRYPT_OK) {
54 | goto LBL_ERR;
55 | }
56 |
57 | if ((err = hmac_process(hmac, in, inlen)) != CRYPT_OK) {
58 | goto LBL_ERR;
59 | }
60 |
61 | if ((err = hmac_done(hmac, out, outlen)) != CRYPT_OK) {
62 | goto LBL_ERR;
63 | }
64 |
65 | err = CRYPT_OK;
66 | LBL_ERR:
67 | #ifdef LTC_CLEAN_STACK
68 | zeromem(hmac, sizeof(hmac_state));
69 | #endif
70 |
71 | XFREE(hmac);
72 | return err;
73 | }
74 |
75 | #endif
76 |
77 |
--------------------------------------------------------------------------------
/hmac_process.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file hmac_process.c
7 | HMAC support, process data, Tom St Denis/Dobes Vandermeer
8 | */
9 |
10 | #ifdef LTC_HMAC
11 |
12 | /**
13 | Process data through HMAC
14 | @param hmac The hmac state
15 | @param in The data to send through HMAC
16 | @param inlen The length of the data to HMAC (octets)
17 | @return CRYPT_OK if successful
18 | */
19 | int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen)
20 | {
21 | int err;
22 | LTC_ARGCHK(hmac != NULL);
23 | LTC_ARGCHK(in != NULL);
24 | if ((err = hash_is_valid(hmac->hash)) != CRYPT_OK) {
25 | return err;
26 | }
27 | return hash_descriptor[hmac->hash].process(&hmac->md, in, inlen);
28 | }
29 |
30 | #endif
31 |
32 |
--------------------------------------------------------------------------------
/pkcs_5_2.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file pkcs_5_2.c
7 | PKCS #5, Algorithm #2, Tom St Denis
8 | */
9 | #ifdef LTC_PKCS_5
10 |
11 | /**
12 | Execute PKCS #5 v2
13 | @param password The input password (or key)
14 | @param password_len The length of the password (octets)
15 | @param salt The salt (or nonce)
16 | @param salt_len The length of the salt (octets)
17 | @param iteration_count # of iterations desired for PKCS #5 v2 [read specs for more]
18 | @param hash_idx The index of the hash desired
19 | @param out [out] The destination for this algorithm
20 | @param outlen [in/out] The max size and resulting size of the algorithm output
21 | @return CRYPT_OK if successful
22 | */
23 | int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
24 | const unsigned char *salt, unsigned long salt_len,
25 | int iteration_count, int hash_idx,
26 | unsigned char *out, unsigned long *outlen)
27 | {
28 | int err, itts;
29 | ulong32 blkno;
30 | unsigned long stored, left, x, y;
31 | unsigned char *buf[2];
32 | hmac_state *hmac;
33 |
34 | LTC_ARGCHK(password != NULL);
35 | LTC_ARGCHK(salt != NULL);
36 | LTC_ARGCHK(out != NULL);
37 | LTC_ARGCHK(outlen != NULL);
38 |
39 | /* test hash IDX */
40 | if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
41 | return err;
42 | }
43 |
44 | buf[0] = XMALLOC(MAXBLOCKSIZE * 2);
45 | hmac = XMALLOC(sizeof(hmac_state));
46 | if (hmac == NULL || buf[0] == NULL) {
47 | if (hmac != NULL) {
48 | XFREE(hmac);
49 | }
50 | if (buf[0] != NULL) {
51 | XFREE(buf[0]);
52 | }
53 | return CRYPT_MEM;
54 | }
55 | /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
56 | buf[1] = buf[0] + MAXBLOCKSIZE;
57 |
58 | left = *outlen;
59 | blkno = 1;
60 | stored = 0;
61 | while (left != 0) {
62 | /* process block number blkno */
63 | zeromem(buf[0], MAXBLOCKSIZE*2);
64 |
65 | /* store current block number and increment for next pass */
66 | STORE32H(blkno, buf[1]);
67 | ++blkno;
68 |
69 | /* get PRF(P, S||int(blkno)) */
70 | if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) {
71 | goto LBL_ERR;
72 | }
73 | if ((err = hmac_process(hmac, salt, salt_len)) != CRYPT_OK) {
74 | goto LBL_ERR;
75 | }
76 | if ((err = hmac_process(hmac, buf[1], 4)) != CRYPT_OK) {
77 | goto LBL_ERR;
78 | }
79 | x = MAXBLOCKSIZE;
80 | if ((err = hmac_done(hmac, buf[0], &x)) != CRYPT_OK) {
81 | goto LBL_ERR;
82 | }
83 |
84 | /* now compute repeated and XOR it in buf[1] */
85 | XMEMCPY(buf[1], buf[0], x);
86 | for (itts = 1; itts < iteration_count; ++itts) {
87 | if ((err = hmac_memory(hash_idx, password, password_len, buf[0], x, buf[0], &x)) != CRYPT_OK) {
88 | goto LBL_ERR;
89 | }
90 | for (y = 0; y < x; y++) {
91 | buf[1][y] ^= buf[0][y];
92 | }
93 | }
94 |
95 | /* now emit upto x bytes of buf[1] to output */
96 | for (y = 0; y < x && left != 0; ++y) {
97 | out[stored++] = buf[1][y];
98 | --left;
99 | }
100 | }
101 | *outlen = stored;
102 |
103 | err = CRYPT_OK;
104 | LBL_ERR:
105 | #ifdef LTC_CLEAN_STACK
106 | zeromem(buf[0], MAXBLOCKSIZE*2);
107 | zeromem(hmac, sizeof(hmac_state));
108 | #endif
109 |
110 | XFREE(hmac);
111 | XFREE(buf[0]);
112 |
113 | return err;
114 | }
115 |
116 | #endif
117 |
118 |
--------------------------------------------------------------------------------
/sha1.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file sha1.c
7 | LTC_SHA1 code by Tom St Denis
8 | */
9 |
10 |
11 | #ifdef LTC_SHA1
12 |
13 | const struct ltc_hash_descriptor sha1_desc =
14 | {
15 | "sha1",
16 | 2,
17 | 20,
18 | 64,
19 |
20 | /* OID */
21 | { 1, 3, 14, 3, 2, 26, },
22 | 6,
23 |
24 | &sha1_init,
25 | &sha1_process,
26 | &sha1_done,
27 | &sha1_test,
28 | NULL
29 | };
30 |
31 | #define F0(x,y,z) (z ^ (x & (y ^ z)))
32 | #define F1(x,y,z) (x ^ y ^ z)
33 | #define F2(x,y,z) ((x & y) | (z & (x | y)))
34 | #define F3(x,y,z) (x ^ y ^ z)
35 |
36 | #ifdef LTC_CLEAN_STACK
37 | static int ss_sha1_compress(hash_state *md, const unsigned char *buf)
38 | #else
39 | static int s_sha1_compress(hash_state *md, const unsigned char *buf)
40 | #endif
41 | {
42 | ulong32 a,b,c,d,e,W[80],i;
43 | #ifdef LTC_SMALL_CODE
44 | ulong32 t;
45 | #endif
46 |
47 | /* copy the state into 512-bits into W[0..15] */
48 | for (i = 0; i < 16; i++) {
49 | LOAD32H(W[i], buf + (4*i));
50 | }
51 |
52 | /* copy state */
53 | a = md->sha1.state[0];
54 | b = md->sha1.state[1];
55 | c = md->sha1.state[2];
56 | d = md->sha1.state[3];
57 | e = md->sha1.state[4];
58 |
59 | /* expand it */
60 | for (i = 16; i < 80; i++) {
61 | W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
62 | }
63 |
64 | /* compress */
65 | /* round one */
66 | #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
67 | #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
68 | #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
69 | #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
70 |
71 | #ifdef LTC_SMALL_CODE
72 |
73 | for (i = 0; i < 20; ) {
74 | FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
75 | }
76 |
77 | for (; i < 40; ) {
78 | FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
79 | }
80 |
81 | for (; i < 60; ) {
82 | FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
83 | }
84 |
85 | for (; i < 80; ) {
86 | FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
87 | }
88 |
89 | #else
90 |
91 | for (i = 0; i < 20; ) {
92 | FF0(a,b,c,d,e,i++);
93 | FF0(e,a,b,c,d,i++);
94 | FF0(d,e,a,b,c,i++);
95 | FF0(c,d,e,a,b,i++);
96 | FF0(b,c,d,e,a,i++);
97 | }
98 |
99 | /* round two */
100 | for (; i < 40; ) {
101 | FF1(a,b,c,d,e,i++);
102 | FF1(e,a,b,c,d,i++);
103 | FF1(d,e,a,b,c,i++);
104 | FF1(c,d,e,a,b,i++);
105 | FF1(b,c,d,e,a,i++);
106 | }
107 |
108 | /* round three */
109 | for (; i < 60; ) {
110 | FF2(a,b,c,d,e,i++);
111 | FF2(e,a,b,c,d,i++);
112 | FF2(d,e,a,b,c,i++);
113 | FF2(c,d,e,a,b,i++);
114 | FF2(b,c,d,e,a,i++);
115 | }
116 |
117 | /* round four */
118 | for (; i < 80; ) {
119 | FF3(a,b,c,d,e,i++);
120 | FF3(e,a,b,c,d,i++);
121 | FF3(d,e,a,b,c,i++);
122 | FF3(c,d,e,a,b,i++);
123 | FF3(b,c,d,e,a,i++);
124 | }
125 | #endif
126 |
127 | #undef FF0
128 | #undef FF1
129 | #undef FF2
130 | #undef FF3
131 |
132 | /* store */
133 | md->sha1.state[0] = md->sha1.state[0] + a;
134 | md->sha1.state[1] = md->sha1.state[1] + b;
135 | md->sha1.state[2] = md->sha1.state[2] + c;
136 | md->sha1.state[3] = md->sha1.state[3] + d;
137 | md->sha1.state[4] = md->sha1.state[4] + e;
138 |
139 | return CRYPT_OK;
140 | }
141 |
142 | #ifdef LTC_CLEAN_STACK
143 | static int s_sha1_compress(hash_state *md, const unsigned char *buf)
144 | {
145 | int err;
146 | err = ss_sha1_compress(md, buf);
147 | burn_stack(sizeof(ulong32) * 87);
148 | return err;
149 | }
150 | #endif
151 |
152 | /**
153 | Initialize the hash state
154 | @param md The hash state you wish to initialize
155 | @return CRYPT_OK if successful
156 | */
157 | int sha1_init(hash_state * md)
158 | {
159 | LTC_ARGCHK(md != NULL);
160 | md->sha1.state[0] = 0x67452301UL;
161 | md->sha1.state[1] = 0xefcdab89UL;
162 | md->sha1.state[2] = 0x98badcfeUL;
163 | md->sha1.state[3] = 0x10325476UL;
164 | md->sha1.state[4] = 0xc3d2e1f0UL;
165 | md->sha1.curlen = 0;
166 | md->sha1.length = 0;
167 | return CRYPT_OK;
168 | }
169 |
170 | /**
171 | Process a block of memory though the hash
172 | @param md The hash state
173 | @param in The data to hash
174 | @param inlen The length of the data (octets)
175 | @return CRYPT_OK if successful
176 | */
177 | HASH_PROCESS(sha1_process, s_sha1_compress, sha1, 64)
178 |
179 | /**
180 | Terminate the hash to get the digest
181 | @param md The hash state
182 | @param out [out] The destination of the hash (20 bytes)
183 | @return CRYPT_OK if successful
184 | */
185 | int sha1_done(hash_state * md, unsigned char *out)
186 | {
187 | int i;
188 |
189 | LTC_ARGCHK(md != NULL);
190 | LTC_ARGCHK(out != NULL);
191 |
192 | if (md->sha1.curlen >= sizeof(md->sha1.buf)) {
193 | return CRYPT_INVALID_ARG;
194 | }
195 |
196 | /* increase the length of the message */
197 | md->sha1.length += md->sha1.curlen * 8;
198 |
199 | /* append the '1' bit */
200 | md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80;
201 |
202 | /* if the length is currently above 56 bytes we append zeros
203 | * then compress. Then we can fall back to padding zeros and length
204 | * encoding like normal.
205 | */
206 | if (md->sha1.curlen > 56) {
207 | while (md->sha1.curlen < 64) {
208 | md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
209 | }
210 | s_sha1_compress(md, md->sha1.buf);
211 | md->sha1.curlen = 0;
212 | }
213 |
214 | /* pad upto 56 bytes of zeroes */
215 | while (md->sha1.curlen < 56) {
216 | md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
217 | }
218 |
219 | /* store length */
220 | STORE64H(md->sha1.length, md->sha1.buf+56);
221 | s_sha1_compress(md, md->sha1.buf);
222 |
223 | /* copy output */
224 | for (i = 0; i < 5; i++) {
225 | STORE32H(md->sha1.state[i], out+(4*i));
226 | }
227 | #ifdef LTC_CLEAN_STACK
228 | zeromem(md, sizeof(hash_state));
229 | #endif
230 | return CRYPT_OK;
231 | }
232 |
233 | /**
234 | Self-test the hash
235 | @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
236 | */
237 | int sha1_test(void)
238 | {
239 | #ifndef LTC_TEST
240 | return CRYPT_NOP;
241 | #else
242 | static const struct {
243 | const char *msg;
244 | unsigned char hash[20];
245 | } tests[] = {
246 | { "abc",
247 | { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
248 | 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
249 | 0x9c, 0xd0, 0xd8, 0x9d }
250 | },
251 | { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
252 | { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
253 | 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
254 | 0xE5, 0x46, 0x70, 0xF1 }
255 | }
256 | };
257 |
258 | int i;
259 | unsigned char tmp[20];
260 | hash_state md;
261 |
262 | for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
263 | sha1_init(&md);
264 | sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)XSTRLEN(tests[i].msg));
265 | sha1_done(&md, tmp);
266 | if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA1", i)) {
267 | return CRYPT_FAIL_TESTVECTOR;
268 | }
269 | }
270 | return CRYPT_OK;
271 | #endif
272 | }
273 |
274 | #endif
275 |
276 |
277 |
--------------------------------------------------------------------------------
/sqlcipher.go:
--------------------------------------------------------------------------------
1 | package sqlite3
2 |
3 | import (
4 | "bytes"
5 | "errors"
6 | "os"
7 | )
8 |
9 | // sqlite3Header defines the header string used by SQLite 3.
10 | var sqlite3Header = []byte("SQLite format 3\000")
11 |
12 | // IsEncrypted returns true, if the database with the given filename is
13 | // encrypted, and false otherwise.
14 | // If the database header cannot be read properly an error is returned.
15 | func IsEncrypted(filename string) (bool, error) {
16 | // open file
17 | db, err := os.Open(filename)
18 | if err != nil {
19 | return false, err
20 | }
21 | defer db.Close()
22 | // read header
23 | var header [16]byte
24 | n, err := db.Read(header[:])
25 | if err != nil {
26 | return false, err
27 | }
28 | if n != len(header) {
29 | return false, errors.New("go-sqlcipher: could not read full header")
30 | }
31 | // SQLCipher encrypts also the header, the file is encrypted if the read
32 | // header does not equal the header string used by SQLite 3.
33 | encrypted := !bytes.Equal(header[:], sqlite3Header)
34 | return encrypted, nil
35 | }
36 |
--------------------------------------------------------------------------------
/sqlcipher_test.go:
--------------------------------------------------------------------------------
1 | package sqlite3_test
2 |
3 | import (
4 | "crypto/rand"
5 | "database/sql"
6 | "encoding/hex"
7 | "errors"
8 | "fmt"
9 | "io"
10 | "io/ioutil"
11 | "log"
12 | "net/url"
13 | "os"
14 | "path/filepath"
15 | "testing"
16 |
17 | sqlite3 "github.com/mutecomm/go-sqlcipher/v4"
18 | "github.com/stretchr/testify/assert"
19 | "github.com/stretchr/testify/require"
20 | )
21 |
22 | var (
23 | db *sql.DB
24 | testDir = "go-sqlcipher_test"
25 | tables = `
26 | CREATE TABLE KeyValueStore (
27 | KeyEntry TEXT NOT NULL UNIQUE,
28 | ValueEntry TEXT NOT NULL
29 | );`
30 | )
31 |
32 | func init() {
33 | // create DB
34 | key := url.QueryEscape("passphrase")
35 | tmpdir, err := ioutil.TempDir("", testDir)
36 | if err != nil {
37 | panic(err)
38 | }
39 | dbname := filepath.Join(tmpdir, "sqlcipher_test")
40 | dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s&_pragma_cipher_page_size=4096", key)
41 | db, err = sql.Open("sqlite3", dbnameWithDSN)
42 | if err != nil {
43 | panic(err)
44 | }
45 | _, err = db.Exec(tables)
46 | if err != nil {
47 | panic(err)
48 | }
49 | db.Close()
50 | // make sure DB is encrypted
51 | encrypted, err := sqlite3.IsEncrypted(dbname)
52 | if err != nil {
53 | panic(err)
54 | }
55 | if !encrypted {
56 | panic(errors.New("go-sqlcipher: DB not encrypted"))
57 | }
58 | // open DB for testing
59 | db, err = sql.Open("sqlite3", dbnameWithDSN)
60 | if err != nil {
61 | panic(err)
62 | }
63 | _, err = db.Exec("SELECT count(*) FROM sqlite_master;")
64 | if err != nil {
65 | panic(err)
66 | }
67 | }
68 |
69 | var mapping = map[string]string{
70 | "foo": "one",
71 | "bar": "two",
72 | "baz": "three",
73 | }
74 |
75 | func TestSQLCipherParallelInsert(t *testing.T) {
76 | t.Parallel()
77 | insertValueQuery, err := db.Prepare("INSERT INTO KeyValueStore (KeyEntry, ValueEntry) VALUES (?, ?);")
78 | require.NoError(t, err)
79 | for key, value := range mapping {
80 | _, err := insertValueQuery.Exec(key, value)
81 | assert.NoError(t, err)
82 | }
83 | }
84 |
85 | func TestSQLCipherParallelSelect(t *testing.T) {
86 | t.Parallel()
87 | getValueQuery, err := db.Prepare("SELECT ValueEntry FROM KeyValueStore WHERE KeyEntry=?;")
88 | if err != nil {
89 | t.Fatal(err)
90 | }
91 | for key, value := range mapping {
92 | var val string
93 | err := getValueQuery.QueryRow(key).Scan(&val)
94 | if err != sql.ErrNoRows {
95 | if assert.NoError(t, err) {
96 | assert.Equal(t, value, val)
97 | }
98 | }
99 | }
100 | }
101 |
102 | func TestSQLCipherIsEncryptedFalse(t *testing.T) {
103 | tmpdir, err := ioutil.TempDir("", testDir)
104 | require.NoError(t, err)
105 | defer os.RemoveAll(tmpdir)
106 | dbname := filepath.Join(tmpdir, "unencrypted.sqlite")
107 | db, err := sql.Open("sqlite3", dbname)
108 | require.NoError(t, err)
109 | defer db.Close()
110 | _, err = db.Exec(tables)
111 | require.NoError(t, err)
112 | encrypted, err := sqlite3.IsEncrypted(dbname)
113 | if assert.NoError(t, err) {
114 | assert.False(t, encrypted)
115 | }
116 | }
117 |
118 | func TestSQLCipherIsEncryptedTrue(t *testing.T) {
119 | tmpdir, err := ioutil.TempDir("", testDir)
120 | require.NoError(t, err)
121 | defer os.RemoveAll(tmpdir)
122 | dbname := filepath.Join(tmpdir, "encrypted.sqlite")
123 | var key [32]byte
124 | _, err = io.ReadFull(rand.Reader, key[:])
125 | require.NoError(t, err)
126 | dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=x'%s'",
127 | hex.EncodeToString(key[:]))
128 | db, err := sql.Open("sqlite3", dbnameWithDSN)
129 | require.NoError(t, err)
130 | defer db.Close()
131 | _, err = db.Exec(tables)
132 | require.NoError(t, err)
133 | encrypted, err := sqlite3.IsEncrypted(dbname)
134 | if assert.NoError(t, err) {
135 | assert.True(t, encrypted)
136 | }
137 | }
138 |
139 | func TestSQLCipher3DB(t *testing.T) {
140 | dbname := filepath.Join("testdata", "sqlcipher3.sqlite3")
141 | dbnameWithDSN := dbname + "?_pragma_key=passphrase&_pragma_cipher_page_size=4096"
142 | // make sure DB is encrypted
143 | encrypted, err := sqlite3.IsEncrypted(dbname)
144 | if err != nil {
145 | t.Fatal(err)
146 | }
147 | if !encrypted {
148 | t.Fatal("go-sqlcipher: DB not encrypted")
149 | }
150 | // open DB for testing
151 | db, err := sql.Open("sqlite3", dbnameWithDSN)
152 | if err != nil {
153 | t.Fatal(err)
154 | }
155 | // should fail
156 | _, err = db.Exec("SELECT count(*) FROM sqlite_master;")
157 | if err == nil {
158 | t.Fatal(errors.New("opening a SQLCipher 3 database with SQLCipher 4 should fail"))
159 | }
160 | }
161 |
162 | func TestSQLCipher4DB(t *testing.T) {
163 | dbname := filepath.Join("testdata", "sqlcipher4.sqlite3")
164 | dbnameWithDSN := dbname + "?_pragma_key=passphrase&_pragma_cipher_page_size=4096"
165 | // make sure DB is encrypted
166 | encrypted, err := sqlite3.IsEncrypted(dbname)
167 | if err != nil {
168 | t.Fatal(err)
169 | }
170 | if !encrypted {
171 | t.Fatal("go-sqlcipher: DB not encrypted")
172 | }
173 | // open DB for testing
174 | db, err := sql.Open("sqlite3", dbnameWithDSN)
175 | if err != nil {
176 | t.Fatal(err)
177 | }
178 | // should succeed
179 | _, err = db.Exec("SELECT count(*) FROM sqlite_master;")
180 | if err != nil {
181 | t.Fatal(err)
182 | }
183 | }
184 |
185 | func ExampleIsEncrypted() {
186 | // create random key
187 | var key [32]byte
188 | _, err := io.ReadFull(rand.Reader, key[:])
189 | if err != nil {
190 | log.Fatal(err)
191 | }
192 | // set DB name
193 | dbname := "go-sqlcipher.sqlite"
194 | dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=x'%s'",
195 | hex.EncodeToString(key[:]))
196 | // create encrypted DB file
197 | db, err := sql.Open("sqlite3", dbnameWithDSN)
198 | if err != nil {
199 | log.Fatal(err)
200 | }
201 | defer os.Remove(dbname)
202 | defer db.Close()
203 | // create table
204 | _, err = db.Exec("CREATE TABLE t(x INTEGER);")
205 | if err != nil {
206 | log.Fatal(err)
207 | }
208 | // make sure database is encrypted
209 | encrypted, err := sqlite3.IsEncrypted(dbname)
210 | if err != nil {
211 | log.Fatal(err)
212 | }
213 | if encrypted {
214 | fmt.Println("DB is encrypted")
215 | } else {
216 | fmt.Println("DB is unencrypted")
217 | }
218 | // Output:
219 | // DB is encrypted
220 | }
221 |
--------------------------------------------------------------------------------
/sqlite3_context.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | /*
9 |
10 | #ifndef USE_LIBSQLITE3
11 | #include
12 | #else
13 | #include
14 | #endif
15 | #include
16 | // These wrappers are necessary because SQLITE_TRANSIENT
17 | // is a pointer constant, and cgo doesn't translate them correctly.
18 |
19 | static inline void my_result_text(sqlite3_context *ctx, char *p, int np) {
20 | sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT);
21 | }
22 |
23 | static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) {
24 | sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT);
25 | }
26 | */
27 | import "C"
28 |
29 | import (
30 | "math"
31 | "reflect"
32 | "unsafe"
33 | )
34 |
35 | const i64 = unsafe.Sizeof(int(0)) > 4
36 |
37 | // SQLiteContext behave sqlite3_context
38 | type SQLiteContext C.sqlite3_context
39 |
40 | // ResultBool sets the result of an SQL function.
41 | func (c *SQLiteContext) ResultBool(b bool) {
42 | if b {
43 | c.ResultInt(1)
44 | } else {
45 | c.ResultInt(0)
46 | }
47 | }
48 |
49 | // ResultBlob sets the result of an SQL function.
50 | // See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html
51 | func (c *SQLiteContext) ResultBlob(b []byte) {
52 | if i64 && len(b) > math.MaxInt32 {
53 | C.sqlite3_result_error_toobig((*C.sqlite3_context)(c))
54 | return
55 | }
56 | var p *byte
57 | if len(b) > 0 {
58 | p = &b[0]
59 | }
60 | C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b)))
61 | }
62 |
63 | // ResultDouble sets the result of an SQL function.
64 | // See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html
65 | func (c *SQLiteContext) ResultDouble(d float64) {
66 | C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d))
67 | }
68 |
69 | // ResultInt sets the result of an SQL function.
70 | // See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html
71 | func (c *SQLiteContext) ResultInt(i int) {
72 | if i64 && (i > math.MaxInt32 || i < math.MinInt32) {
73 | C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i))
74 | } else {
75 | C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i))
76 | }
77 | }
78 |
79 | // ResultInt64 sets the result of an SQL function.
80 | // See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html
81 | func (c *SQLiteContext) ResultInt64(i int64) {
82 | C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i))
83 | }
84 |
85 | // ResultNull sets the result of an SQL function.
86 | // See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html
87 | func (c *SQLiteContext) ResultNull() {
88 | C.sqlite3_result_null((*C.sqlite3_context)(c))
89 | }
90 |
91 | // ResultText sets the result of an SQL function.
92 | // See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html
93 | func (c *SQLiteContext) ResultText(s string) {
94 | h := (*reflect.StringHeader)(unsafe.Pointer(&s))
95 | cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len)
96 | C.my_result_text((*C.sqlite3_context)(c), cs, l)
97 | }
98 |
99 | // ResultZeroblob sets the result of an SQL function.
100 | // See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html
101 | func (c *SQLiteContext) ResultZeroblob(n int) {
102 | C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n))
103 | }
104 |
--------------------------------------------------------------------------------
/sqlite3_func_crypt.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 G.J.R. Timmer .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | import (
9 | "crypto/sha1"
10 | "crypto/sha256"
11 | "crypto/sha512"
12 | )
13 |
14 | // This file provides several different implementations for the
15 | // default embedded sqlite_crypt function.
16 | // This function is uses a caesar-cypher by default
17 | // and is used within the UserAuthentication module to encode
18 | // the password.
19 | //
20 | // The provided functions can be used as an overload to the sqlite_crypt
21 | // function through the use of the RegisterFunc on the connection.
22 | //
23 | // Because the functions can serv a purpose to an end-user
24 | // without using the UserAuthentication module
25 | // the functions are default compiled in.
26 | //
27 | // From SQLITE3 - user-auth.txt
28 | // The sqlite_user.pw field is encoded by a built-in SQL function
29 | // "sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument
30 | // is the plaintext password supplied to the sqlite3_user_authenticate()
31 | // interface. The second argument is the sqlite_user.pw value and is supplied
32 | // so that the function can extract the "salt" used by the password encoder.
33 | // The result of sqlite_crypt(X,Y) is another blob which is the value that
34 | // ends up being stored in sqlite_user.pw. To verify credentials X supplied
35 | // by the sqlite3_user_authenticate() routine, SQLite runs:
36 | //
37 | // sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw)
38 | //
39 | // To compute an appropriate sqlite_user.pw value from a new or modified
40 | // password X, sqlite_crypt(X,NULL) is run. A new random salt is selected
41 | // when the second argument is NULL.
42 | //
43 | // The built-in version of of sqlite_crypt() uses a simple Caesar-cypher
44 | // which prevents passwords from being revealed by searching the raw database
45 | // for ASCII text, but is otherwise trivally broken. For better password
46 | // security, the database should be encrypted using the SQLite Encryption
47 | // Extension or similar technology. Or, the application can use the
48 | // sqlite3_create_function() interface to provide an alternative
49 | // implementation of sqlite_crypt() that computes a stronger password hash,
50 | // perhaps using a cryptographic hash function like SHA1.
51 |
52 | // CryptEncoderSHA1 encodes a password with SHA1
53 | func CryptEncoderSHA1(pass []byte, hash interface{}) []byte {
54 | h := sha1.Sum(pass)
55 | return h[:]
56 | }
57 |
58 | // CryptEncoderSSHA1 encodes a password with SHA1 with the
59 | // configured salt.
60 | func CryptEncoderSSHA1(salt string) func(pass []byte, hash interface{}) []byte {
61 | return func(pass []byte, hash interface{}) []byte {
62 | s := []byte(salt)
63 | p := append(pass, s...)
64 | h := sha1.Sum(p)
65 | return h[:]
66 | }
67 | }
68 |
69 | // CryptEncoderSHA256 encodes a password with SHA256
70 | func CryptEncoderSHA256(pass []byte, hash interface{}) []byte {
71 | h := sha256.Sum256(pass)
72 | return h[:]
73 | }
74 |
75 | // CryptEncoderSSHA256 encodes a password with SHA256
76 | // with the configured salt
77 | func CryptEncoderSSHA256(salt string) func(pass []byte, hash interface{}) []byte {
78 | return func(pass []byte, hash interface{}) []byte {
79 | s := []byte(salt)
80 | p := append(pass, s...)
81 | h := sha256.Sum256(p)
82 | return h[:]
83 | }
84 | }
85 |
86 | // CryptEncoderSHA384 encodes a password with SHA384
87 | func CryptEncoderSHA384(pass []byte, hash interface{}) []byte {
88 | h := sha512.Sum384(pass)
89 | return h[:]
90 | }
91 |
92 | // CryptEncoderSSHA384 encodes a password with SHA384
93 | // with the configured salt
94 | func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte {
95 | return func(pass []byte, hash interface{}) []byte {
96 | s := []byte(salt)
97 | p := append(pass, s...)
98 | h := sha512.Sum384(p)
99 | return h[:]
100 | }
101 | }
102 |
103 | // CryptEncoderSHA512 encodes a password with SHA512
104 | func CryptEncoderSHA512(pass []byte, hash interface{}) []byte {
105 | h := sha512.Sum512(pass)
106 | return h[:]
107 | }
108 |
109 | // CryptEncoderSSHA512 encodes a password with SHA512
110 | // with the configured salt
111 | func CryptEncoderSSHA512(salt string) func(pass []byte, hash interface{}) []byte {
112 | return func(pass []byte, hash interface{}) []byte {
113 | s := []byte(salt)
114 | p := append(pass, s...)
115 | h := sha512.Sum512(p)
116 | return h[:]
117 | }
118 | }
119 |
120 | // EOF
121 |
--------------------------------------------------------------------------------
/sqlite3_func_crypt_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 G.J.R. Timmer .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | import (
9 | "fmt"
10 | "strings"
11 | "testing"
12 | )
13 |
14 | // TestCryptEncoders to increase coverage
15 | func TestCryptEncoders(t *testing.T) {
16 | tests := []struct {
17 | enc string
18 | salt string
19 | expected string
20 | }{
21 | {"sha1", "", "d033e22ae348aeb5660fc2140aec35850c4da997"},
22 | {"sha256", "", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"},
23 | {"sha384", "", "9ca694a90285c034432c9550421b7b9dbd5c0f4b6673f05f6dbce58052ba20e4248041956ee8c9a2ec9f10290cdc0782"},
24 | {"sha512", "", "c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec"},
25 | {"ssha1", "salt", "9bc7aa55f08fdad935c3f8362d3f48bcf70eb280"},
26 | {"ssha256", "salt", "f9a81477552594c79f2abc3fc099daa896a6e3a3590a55ffa392b6000412e80b"},
27 | {"ssha384", "salt", "9ed776b477fcfc1b5e584989e8d770f5e17d98a7643546a63c2b07d4ab00f1348f6b8e73103d3a23554f727136e8c215"},
28 | {"ssha512", "salt", "3c4a79782143337be4492be072abcfe979dd703c00541a8c39a0f3df4bab2029c050cf46fddc47090b5b04ac537b3e78189e3de16e601e859f95c51ac9f6dafb"},
29 | }
30 |
31 | for _, e := range tests {
32 | var fn func(pass []byte, hash interface{}) []byte
33 | switch e.enc {
34 | case "sha1":
35 | fn = CryptEncoderSHA1
36 | case "ssha1":
37 | fn = CryptEncoderSSHA1(e.salt)
38 | case "sha256":
39 | fn = CryptEncoderSHA256
40 | case "ssha256":
41 | fn = CryptEncoderSSHA256(e.salt)
42 | case "sha384":
43 | fn = CryptEncoderSHA384
44 | case "ssha384":
45 | fn = CryptEncoderSSHA384(e.salt)
46 | case "sha512":
47 | fn = CryptEncoderSHA512
48 | case "ssha512":
49 | fn = CryptEncoderSSHA512(e.salt)
50 | }
51 |
52 | h := fn([]byte("admin"), nil)
53 | if strings.Compare(fmt.Sprintf("%x", h), e.expected) != 0 {
54 | t.Fatalf("Invalid %s hash: expected: %s; got: %x", strings.ToUpper(e.enc), e.expected, h)
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/sqlite3_go113_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build go1.13,cgo
7 |
8 | package sqlite3
9 |
10 | import (
11 | "context"
12 | "database/sql"
13 | "database/sql/driver"
14 | "os"
15 | "testing"
16 | )
17 |
18 | func TestBeginTxCancel(t *testing.T) {
19 | srcTempFilename := TempFilename(t)
20 | defer os.Remove(srcTempFilename)
21 |
22 | db, err := sql.Open("sqlite3", srcTempFilename)
23 | if err != nil {
24 | t.Fatal(err)
25 | }
26 |
27 | db.SetMaxOpenConns(10)
28 | db.SetMaxIdleConns(5)
29 |
30 | defer db.Close()
31 | initDatabase(t, db, 100)
32 |
33 | // create several go-routines to expose racy issue
34 | for i := 0; i < 1000; i++ {
35 | func() {
36 | ctx, cancel := context.WithCancel(context.Background())
37 | conn, err := db.Conn(ctx)
38 | if err != nil {
39 | t.Fatal(err)
40 | }
41 | defer func() {
42 | if err := conn.Close(); err != nil {
43 | t.Error(err)
44 | }
45 | }()
46 |
47 | err = conn.Raw(func(driverConn interface{}) error {
48 | d, ok := driverConn.(driver.ConnBeginTx)
49 | if !ok {
50 | t.Fatal("unexpected: wrong type")
51 | }
52 | // checks that conn.Raw can be used to get *SQLiteConn
53 | if _, ok = driverConn.(*SQLiteConn); !ok {
54 | t.Fatalf("conn.Raw() driverConn type=%T, expected *SQLiteConn", driverConn)
55 | }
56 |
57 | go cancel() // make it cancel concurrently with exec("BEGIN");
58 | tx, err := d.BeginTx(ctx, driver.TxOptions{})
59 | switch err {
60 | case nil:
61 | switch err := tx.Rollback(); err {
62 | case nil, sql.ErrTxDone:
63 | default:
64 | return err
65 | }
66 | case context.Canceled:
67 | default:
68 | // must not fail with "cannot start a transaction within a transaction"
69 | return err
70 | }
71 | return nil
72 | })
73 | if err != nil {
74 | t.Fatal(err)
75 | }
76 | }()
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/sqlite3_go18.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 | // +build go1.8
8 |
9 | package sqlite3
10 |
11 | import (
12 | "database/sql/driver"
13 |
14 | "context"
15 | )
16 |
17 | // Ping implement Pinger.
18 | func (c *SQLiteConn) Ping(ctx context.Context) error {
19 | if c.db == nil {
20 | // must be ErrBadConn for sql to close the database
21 | return driver.ErrBadConn
22 | }
23 | return nil
24 | }
25 |
26 | // QueryContext implement QueryerContext.
27 | func (c *SQLiteConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
28 | list := make([]namedValue, len(args))
29 | for i, nv := range args {
30 | list[i] = namedValue(nv)
31 | }
32 | return c.query(ctx, query, list)
33 | }
34 |
35 | // ExecContext implement ExecerContext.
36 | func (c *SQLiteConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
37 | list := make([]namedValue, len(args))
38 | for i, nv := range args {
39 | list[i] = namedValue(nv)
40 | }
41 | return c.exec(ctx, query, list)
42 | }
43 |
44 | // PrepareContext implement ConnPrepareContext.
45 | func (c *SQLiteConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
46 | return c.prepare(ctx, query)
47 | }
48 |
49 | // BeginTx implement ConnBeginTx.
50 | func (c *SQLiteConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
51 | return c.begin(ctx)
52 | }
53 |
54 | // QueryContext implement QueryerContext.
55 | func (s *SQLiteStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
56 | list := make([]namedValue, len(args))
57 | for i, nv := range args {
58 | list[i] = namedValue(nv)
59 | }
60 | return s.query(ctx, list)
61 | }
62 |
63 | // ExecContext implement ExecerContext.
64 | func (s *SQLiteStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
65 | list := make([]namedValue, len(args))
66 | for i, nv := range args {
67 | list[i] = namedValue(nv)
68 | }
69 | return s.exec(ctx, list)
70 | }
71 |
--------------------------------------------------------------------------------
/sqlite3_libsqlite3.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build libsqlite3
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -DUSE_LIBSQLITE3
12 | #cgo linux LDFLAGS: -lsqlite3
13 | #cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3
14 | #cgo darwin CFLAGS: -I/usr/local/opt/sqlite/include
15 | #cgo openbsd LDFLAGS: -lsqlite3
16 | #cgo solaris LDFLAGS: -lsqlite3
17 | #cgo windows LDFLAGS: -lsqlite3
18 | */
19 | import "C"
20 |
--------------------------------------------------------------------------------
/sqlite3_load_extension.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build !sqlite_omit_load_extension
7 |
8 | package sqlite3
9 |
10 | /*
11 | #ifndef USE_LIBSQLITE3
12 | #include
13 | #else
14 | #include
15 | #endif
16 | #include
17 | */
18 | import "C"
19 | import (
20 | "errors"
21 | "unsafe"
22 | )
23 |
24 | func (c *SQLiteConn) loadExtensions(extensions []string) error {
25 | rv := C.sqlite3_enable_load_extension(c.db, 1)
26 | if rv != C.SQLITE_OK {
27 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
28 | }
29 |
30 | for _, extension := range extensions {
31 | if err := c.loadExtension(extension, nil); err != nil {
32 | C.sqlite3_enable_load_extension(c.db, 0)
33 | return err
34 | }
35 | }
36 |
37 | rv = C.sqlite3_enable_load_extension(c.db, 0)
38 | if rv != C.SQLITE_OK {
39 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
40 | }
41 |
42 | return nil
43 | }
44 |
45 | // LoadExtension load the sqlite3 extension.
46 | func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
47 | rv := C.sqlite3_enable_load_extension(c.db, 1)
48 | if rv != C.SQLITE_OK {
49 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
50 | }
51 |
52 | if err := c.loadExtension(lib, &entry); err != nil {
53 | C.sqlite3_enable_load_extension(c.db, 0)
54 | return err
55 | }
56 |
57 | rv = C.sqlite3_enable_load_extension(c.db, 0)
58 | if rv != C.SQLITE_OK {
59 | return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
60 | }
61 |
62 | return nil
63 | }
64 |
65 | func (c *SQLiteConn) loadExtension(lib string, entry *string) error {
66 | clib := C.CString(lib)
67 | defer C.free(unsafe.Pointer(clib))
68 |
69 | var centry *C.char
70 | if entry != nil {
71 | centry = C.CString(*entry)
72 | defer C.free(unsafe.Pointer(centry))
73 | }
74 |
75 | var errMsg *C.char
76 | defer C.sqlite3_free(unsafe.Pointer(errMsg))
77 |
78 | rv := C.sqlite3_load_extension(c.db, clib, centry, &errMsg)
79 | if rv != C.SQLITE_OK {
80 | return errors.New(C.GoString(errMsg))
81 | }
82 |
83 | return nil
84 | }
85 |
--------------------------------------------------------------------------------
/sqlite3_load_extension_omit.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build sqlite_omit_load_extension
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION
12 | */
13 | import "C"
14 | import (
15 | "errors"
16 | )
17 |
18 | func (c *SQLiteConn) loadExtensions(extensions []string) error {
19 | return errors.New("Extensions have been disabled for static builds")
20 | }
21 |
22 | func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
23 | return errors.New("Extensions have been disabled for static builds")
24 | }
25 |
--------------------------------------------------------------------------------
/sqlite3_load_extension_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build !sqlite_omit_load_extension
7 |
8 | package sqlite3
9 |
10 | import (
11 | "database/sql"
12 | "testing"
13 | )
14 |
15 | func TestExtensionsError(t *testing.T) {
16 | sql.Register("sqlite3_TestExtensionsError",
17 | &SQLiteDriver{
18 | Extensions: []string{
19 | "foobar",
20 | },
21 | },
22 | )
23 |
24 | db, err := sql.Open("sqlite3_TestExtensionsError", ":memory:")
25 | if err != nil {
26 | t.Fatal(err)
27 | }
28 | defer db.Close()
29 |
30 | err = db.Ping()
31 | if err == nil {
32 | t.Fatal("expected error loading non-existent extension")
33 | }
34 |
35 | if err.Error() == "not an error" {
36 | t.Fatal("expected error from sqlite3_enable_load_extension to be returned")
37 | }
38 | }
39 |
40 | func TestLoadExtensionError(t *testing.T) {
41 | sql.Register("sqlite3_TestLoadExtensionError",
42 | &SQLiteDriver{
43 | ConnectHook: func(c *SQLiteConn) error {
44 | return c.LoadExtension("foobar", "")
45 | },
46 | },
47 | )
48 |
49 | db, err := sql.Open("sqlite3_TestLoadExtensionError", ":memory:")
50 | if err != nil {
51 | t.Fatal(err)
52 | }
53 | defer db.Close()
54 |
55 | err = db.Ping()
56 | if err == nil {
57 | t.Fatal("expected error loading non-existent extension")
58 | }
59 |
60 | if err.Error() == "not an error" {
61 | t.Fatal("expected error from sqlite3_enable_load_extension to be returned")
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/sqlite3_opt_allow_uri_authority.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_allow_uri_authority
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_ALLOW_URI_AUTHORITY
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_app_armor.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build !windows
8 | // +build sqlite_app_armor
9 |
10 | package sqlite3
11 |
12 | /*
13 | #cgo CFLAGS: -DSQLITE_ENABLE_API_ARMOR
14 | #cgo LDFLAGS: -lm
15 | */
16 | import "C"
17 |
--------------------------------------------------------------------------------
/sqlite3_opt_foreign_keys.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_foreign_keys
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_DEFAULT_FOREIGN_KEYS=1
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_fts3_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 |
8 | package sqlite3
9 |
10 | import (
11 | "database/sql"
12 | "os"
13 | "testing"
14 | )
15 |
16 | func TestFTS3(t *testing.T) {
17 | tempFilename := TempFilename(t)
18 | defer os.Remove(tempFilename)
19 | db, err := sql.Open("sqlite3", tempFilename)
20 | if err != nil {
21 | t.Fatal("Failed to open database:", err)
22 | }
23 | defer db.Close()
24 |
25 | _, err = db.Exec("DROP TABLE foo")
26 | _, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts3(id INTEGER PRIMARY KEY, value TEXT)")
27 | if err != nil {
28 | t.Fatal("Failed to create table:", err)
29 | }
30 |
31 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `今日の 晩御飯は 天麩羅よ`)
32 | if err != nil {
33 | t.Fatal("Failed to insert value:", err)
34 | }
35 |
36 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 2, `今日は いい 天気だ`)
37 | if err != nil {
38 | t.Fatal("Failed to insert value:", err)
39 | }
40 |
41 | rows, err := db.Query("SELECT id, value FROM foo WHERE value MATCH '今日* 天*'")
42 | if err != nil {
43 | t.Fatal("Unable to query foo table:", err)
44 | }
45 | defer rows.Close()
46 |
47 | for rows.Next() {
48 | var id int
49 | var value string
50 |
51 | if err := rows.Scan(&id, &value); err != nil {
52 | t.Error("Unable to scan results:", err)
53 | continue
54 | }
55 |
56 | if id == 1 && value != `今日の 晩御飯は 天麩羅よ` {
57 | t.Error("Value for id 1 should be `今日の 晩御飯は 天麩羅よ`, but:", value)
58 | } else if id == 2 && value != `今日は いい 天気だ` {
59 | t.Error("Value for id 2 should be `今日は いい 天気だ`, but:", value)
60 | }
61 | }
62 |
63 | rows, err = db.Query("SELECT value FROM foo WHERE value MATCH '今日* 天麩羅*'")
64 | if err != nil {
65 | t.Fatal("Unable to query foo table:", err)
66 | }
67 | defer rows.Close()
68 |
69 | var value string
70 | if !rows.Next() {
71 | t.Fatal("Result should be only one")
72 | }
73 |
74 | if err := rows.Scan(&value); err != nil {
75 | t.Fatal("Unable to scan results:", err)
76 | }
77 |
78 | if value != `今日の 晩御飯は 天麩羅よ` {
79 | t.Fatal("Value should be `今日の 晩御飯は 天麩羅よ`, but:", value)
80 | }
81 |
82 | if rows.Next() {
83 | t.Fatal("Result should be only one")
84 | }
85 | }
86 |
87 | func TestFTS4(t *testing.T) {
88 | tempFilename := TempFilename(t)
89 | defer os.Remove(tempFilename)
90 | db, err := sql.Open("sqlite3", tempFilename)
91 | if err != nil {
92 | t.Fatal("Failed to open database:", err)
93 | }
94 | defer db.Close()
95 |
96 | _, err = db.Exec("DROP TABLE foo")
97 | _, err = db.Exec("CREATE VIRTUAL TABLE foo USING fts4(tokenize=unicode61, id INTEGER PRIMARY KEY, value TEXT)")
98 | switch {
99 | case err != nil && err.Error() == "unknown tokenizer: unicode61":
100 | t.Skip("FTS4 not supported")
101 | case err != nil:
102 | t.Fatal("Failed to create table:", err)
103 | }
104 |
105 | _, err = db.Exec("INSERT INTO foo(id, value) VALUES(?, ?)", 1, `février`)
106 | if err != nil {
107 | t.Fatal("Failed to insert value:", err)
108 | }
109 |
110 | rows, err := db.Query("SELECT value FROM foo WHERE value MATCH 'fevrier'")
111 | if err != nil {
112 | t.Fatal("Unable to query foo table:", err)
113 | }
114 | defer rows.Close()
115 |
116 | var value string
117 | if !rows.Next() {
118 | t.Fatal("Result should be only one")
119 | }
120 |
121 | if err := rows.Scan(&value); err != nil {
122 | t.Fatal("Unable to scan results:", err)
123 | }
124 |
125 | if value != `février` {
126 | t.Fatal("Value should be `février`, but:", value)
127 | }
128 |
129 | if rows.Next() {
130 | t.Fatal("Result should be only one")
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/sqlite3_opt_fts5.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build sqlite_fts5 fts5
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -DSQLITE_ENABLE_FTS5
12 | #cgo LDFLAGS: -lm
13 | */
14 | import "C"
15 |
--------------------------------------------------------------------------------
/sqlite3_opt_icu.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build sqlite_icu icu
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo LDFLAGS: -licuuc -licui18n
12 | #cgo CFLAGS: -DSQLITE_ENABLE_ICU
13 | #cgo darwin CFLAGS: -I/usr/local/opt/icu4c/include
14 | #cgo darwin LDFLAGS: -L/usr/local/opt/icu4c/lib
15 | #cgo openbsd LDFLAGS: -lsqlite3
16 | */
17 | import "C"
18 |
--------------------------------------------------------------------------------
/sqlite3_opt_introspect.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 |
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_introspect
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_INTROSPECTION_PRAGMAS
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_json1.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build sqlite_json sqlite_json1 json1
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -DSQLITE_ENABLE_JSON1
12 | */
13 | import "C"
14 |
--------------------------------------------------------------------------------
/sqlite3_opt_preupdate.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 G.J.R. Timmer .
2 | // Copyright (C) 2018 segment.com
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build cgo
8 |
9 | package sqlite3
10 |
11 | // SQLitePreUpdateData represents all of the data available during a
12 | // pre-update hook call.
13 | type SQLitePreUpdateData struct {
14 | Conn *SQLiteConn
15 | Op int
16 | DatabaseName string
17 | TableName string
18 | OldRowID int64
19 | NewRowID int64
20 | }
21 |
--------------------------------------------------------------------------------
/sqlite3_opt_preupdate_hook.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 G.J.R. Timmer .
2 | // Copyright (C) 2018 segment.com
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_preupdate_hook
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_ENABLE_PREUPDATE_HOOK
13 | #cgo LDFLAGS: -lm
14 |
15 | #ifndef USE_LIBSQLITE3
16 | #include
17 | #else
18 | #include
19 | #endif
20 | #include
21 | #include
22 |
23 | void preUpdateHookTrampoline(void*, sqlite3 *, int, char *, char *, sqlite3_int64, sqlite3_int64);
24 | */
25 | import "C"
26 | import (
27 | "errors"
28 | "unsafe"
29 | )
30 |
31 | // RegisterPreUpdateHook sets the pre-update hook for a connection.
32 | //
33 | // The callback is passed a SQLitePreUpdateData struct with the data for
34 | // the update, as well as methods for fetching copies of impacted data.
35 | //
36 | // If there is an existing update hook for this connection, it will be
37 | // removed. If callback is nil the existing hook (if any) will be removed
38 | // without creating a new one.
39 | func (c *SQLiteConn) RegisterPreUpdateHook(callback func(SQLitePreUpdateData)) {
40 | if callback == nil {
41 | C.sqlite3_preupdate_hook(c.db, nil, nil)
42 | } else {
43 | C.sqlite3_preupdate_hook(c.db, (*[0]byte)(unsafe.Pointer(C.preUpdateHookTrampoline)), unsafe.Pointer(newHandle(c, callback)))
44 | }
45 | }
46 |
47 | // Depth returns the source path of the write, see sqlite3_preupdate_depth()
48 | func (d *SQLitePreUpdateData) Depth() int {
49 | return int(C.sqlite3_preupdate_depth(d.Conn.db))
50 | }
51 |
52 | // Count returns the number of columns in the row
53 | func (d *SQLitePreUpdateData) Count() int {
54 | return int(C.sqlite3_preupdate_count(d.Conn.db))
55 | }
56 |
57 | func (d *SQLitePreUpdateData) row(dest []interface{}, new bool) error {
58 | for i := 0; i < d.Count() && i < len(dest); i++ {
59 | var val *C.sqlite3_value
60 | var src interface{}
61 |
62 | // Initially I tried making this just a function pointer argument, but
63 | // it's absurdly complicated to pass C function pointers.
64 | if new {
65 | C.sqlite3_preupdate_new(d.Conn.db, C.int(i), &val)
66 | } else {
67 | C.sqlite3_preupdate_old(d.Conn.db, C.int(i), &val)
68 | }
69 |
70 | switch C.sqlite3_value_type(val) {
71 | case C.SQLITE_INTEGER:
72 | src = int64(C.sqlite3_value_int64(val))
73 | case C.SQLITE_FLOAT:
74 | src = float64(C.sqlite3_value_double(val))
75 | case C.SQLITE_BLOB:
76 | len := C.sqlite3_value_bytes(val)
77 | blobptr := C.sqlite3_value_blob(val)
78 | src = C.GoBytes(blobptr, len)
79 | case C.SQLITE_TEXT:
80 | len := C.sqlite3_value_bytes(val)
81 | cstrptr := unsafe.Pointer(C.sqlite3_value_text(val))
82 | src = C.GoBytes(cstrptr, len)
83 | case C.SQLITE_NULL:
84 | src = nil
85 | }
86 |
87 | err := convertAssign(&dest[i], src)
88 | if err != nil {
89 | return err
90 | }
91 | }
92 |
93 | return nil
94 | }
95 |
96 | // Old populates dest with the row data to be replaced. This works similar to
97 | // database/sql's Rows.Scan()
98 | func (d *SQLitePreUpdateData) Old(dest ...interface{}) error {
99 | if d.Op == SQLITE_INSERT {
100 | return errors.New("There is no old row for INSERT operations")
101 | }
102 | return d.row(dest, false)
103 | }
104 |
105 | // New populates dest with the replacement row data. This works similar to
106 | // database/sql's Rows.Scan()
107 | func (d *SQLitePreUpdateData) New(dest ...interface{}) error {
108 | if d.Op == SQLITE_DELETE {
109 | return errors.New("There is no new row for DELETE operations")
110 | }
111 | return d.row(dest, true)
112 | }
113 |
--------------------------------------------------------------------------------
/sqlite3_opt_preupdate_hook_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 G.J.R. Timmer .
2 | // Copyright (C) 2018 segment.com
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_preupdate_hook
8 |
9 | package sqlite3
10 |
11 | import (
12 | "database/sql"
13 | "testing"
14 | )
15 |
16 | type preUpdateHookDataForTest struct {
17 | databaseName string
18 | tableName string
19 | count int
20 | op int
21 | oldRow []interface{}
22 | newRow []interface{}
23 | }
24 |
25 | func TestPreUpdateHook(t *testing.T) {
26 | var events []preUpdateHookDataForTest
27 |
28 | sql.Register("sqlite3_PreUpdateHook", &SQLiteDriver{
29 | ConnectHook: func(conn *SQLiteConn) error {
30 | conn.RegisterPreUpdateHook(func(data SQLitePreUpdateData) {
31 | eval := -1
32 | oldRow := []interface{}{eval}
33 | if data.Op != SQLITE_INSERT {
34 | err := data.Old(oldRow...)
35 | if err != nil {
36 | t.Fatalf("Unexpected error calling SQLitePreUpdateData.Old: %v", err)
37 | }
38 | }
39 |
40 | eval2 := -1
41 | newRow := []interface{}{eval2}
42 | if data.Op != SQLITE_DELETE {
43 | err := data.New(newRow...)
44 | if err != nil {
45 | t.Fatalf("Unexpected error calling SQLitePreUpdateData.New: %v", err)
46 | }
47 | }
48 |
49 | // tests dest bound checks in loop
50 | var tooSmallRow []interface{}
51 | if data.Op != SQLITE_INSERT {
52 | err := data.Old(tooSmallRow...)
53 | if err != nil {
54 | t.Fatalf("Unexpected error calling SQLitePreUpdateData.Old: %v", err)
55 | }
56 | if len(tooSmallRow) != 0 {
57 | t.Errorf("Expected tooSmallRow to be empty, got: %v", tooSmallRow)
58 | }
59 | }
60 |
61 | events = append(events, preUpdateHookDataForTest{
62 | databaseName: data.DatabaseName,
63 | tableName: data.TableName,
64 | count: data.Count(),
65 | op: data.Op,
66 | oldRow: oldRow,
67 | newRow: newRow,
68 | })
69 | })
70 | return nil
71 | },
72 | })
73 |
74 | db, err := sql.Open("sqlite3_PreUpdateHook", ":memory:")
75 | if err != nil {
76 | t.Fatal("Failed to open database:", err)
77 | }
78 | defer db.Close()
79 |
80 | statements := []string{
81 | "create table foo (id integer primary key)",
82 | "insert into foo values (9)",
83 | "update foo set id = 99 where id = 9",
84 | "delete from foo where id = 99",
85 | }
86 | for _, statement := range statements {
87 | _, err = db.Exec(statement)
88 | if err != nil {
89 | t.Fatalf("Unable to prepare test data [%v]: %v", statement, err)
90 | }
91 | }
92 |
93 | if len(events) != 3 {
94 | t.Errorf("Events should be 3 entries, got: %d", len(events))
95 | }
96 |
97 | if events[0].op != SQLITE_INSERT {
98 | t.Errorf("Op isn't as expected: %v", events[0].op)
99 | }
100 |
101 | if events[1].op != SQLITE_UPDATE {
102 | t.Errorf("Op isn't as expected: %v", events[1].op)
103 | }
104 |
105 | if events[1].count != 1 {
106 | t.Errorf("Expected event row 1 to have 1 column, had: %v", events[1].count)
107 | }
108 |
109 | newRow_0_0 := events[0].newRow[0].(int64)
110 | if newRow_0_0 != 9 {
111 | t.Errorf("Expected event row 0 new column 0 to be == 9, got: %v", newRow_0_0)
112 | }
113 |
114 | oldRow_1_0 := events[1].oldRow[0].(int64)
115 | if oldRow_1_0 != 9 {
116 | t.Errorf("Expected event row 1 old column 0 to be == 9, got: %v", oldRow_1_0)
117 | }
118 |
119 | newRow_1_0 := events[1].newRow[0].(int64)
120 | if newRow_1_0 != 99 {
121 | t.Errorf("Expected event row 1 new column 0 to be == 99, got: %v", newRow_1_0)
122 | }
123 |
124 | oldRow_2_0 := events[2].oldRow[0].(int64)
125 | if oldRow_2_0 != 99 {
126 | t.Errorf("Expected event row 1 new column 0 to be == 99, got: %v", oldRow_2_0)
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/sqlite3_opt_preupdate_omit.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 G.J.R. Timmer .
2 | // Copyright (C) 2018 segment.com
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build !sqlite_preupdate_hook,cgo
8 |
9 | package sqlite3
10 |
11 | // RegisterPreUpdateHook sets the pre-update hook for a connection.
12 | //
13 | // The callback is passed a SQLitePreUpdateData struct with the data for
14 | // the update, as well as methods for fetching copies of impacted data.
15 | //
16 | // If there is an existing update hook for this connection, it will be
17 | // removed. If callback is nil the existing hook (if any) will be removed
18 | // without creating a new one.
19 | func (c *SQLiteConn) RegisterPreUpdateHook(callback func(SQLitePreUpdateData)) {
20 | // NOOP
21 | }
22 |
--------------------------------------------------------------------------------
/sqlite3_opt_secure_delete.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_secure_delete
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_SECURE_DELETE=1
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_secure_delete_fast.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_secure_delete_fast
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_SECURE_DELETE=FAST
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_stat4.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_stat4
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_ENABLE_STAT4
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_unlock_notify.c:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
7 | #include
8 | #include
9 |
10 | extern int unlock_notify_wait(sqlite3 *db);
11 |
12 | int
13 | _sqlite3_step_blocking(sqlite3_stmt *stmt)
14 | {
15 | int rv;
16 | sqlite3* db;
17 |
18 | db = sqlite3_db_handle(stmt);
19 | for (;;) {
20 | rv = sqlite3_step(stmt);
21 | if (rv != SQLITE_LOCKED) {
22 | break;
23 | }
24 | if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
25 | break;
26 | }
27 | rv = unlock_notify_wait(db);
28 | if (rv != SQLITE_OK) {
29 | break;
30 | }
31 | sqlite3_reset(stmt);
32 | }
33 |
34 | return rv;
35 | }
36 |
37 | int
38 | _sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes)
39 | {
40 | int rv;
41 | sqlite3* db;
42 |
43 | db = sqlite3_db_handle(stmt);
44 | for (;;) {
45 | rv = sqlite3_step(stmt);
46 | if (rv!=SQLITE_LOCKED) {
47 | break;
48 | }
49 | if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
50 | break;
51 | }
52 | rv = unlock_notify_wait(db);
53 | if (rv != SQLITE_OK) {
54 | break;
55 | }
56 | sqlite3_reset(stmt);
57 | }
58 |
59 | *rowid = (long long) sqlite3_last_insert_rowid(db);
60 | *changes = (long long) sqlite3_changes(db);
61 | return rv;
62 | }
63 |
64 | int
65 | _sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
66 | {
67 | int rv;
68 |
69 | for (;;) {
70 | rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
71 | if (rv!=SQLITE_LOCKED) {
72 | break;
73 | }
74 | if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
75 | break;
76 | }
77 | rv = unlock_notify_wait(db);
78 | if (rv != SQLITE_OK) {
79 | break;
80 | }
81 | }
82 |
83 | return rv;
84 | }
85 | #endif
86 |
--------------------------------------------------------------------------------
/sqlite3_opt_unlock_notify.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 | // +build sqlite_unlock_notify
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
13 |
14 | #include
15 | #include
16 |
17 | extern void unlock_notify_callback(void *arg, int argc);
18 | */
19 | import "C"
20 | import (
21 | "fmt"
22 | "math"
23 | "sync"
24 | "unsafe"
25 | )
26 |
27 | type unlock_notify_table struct {
28 | sync.Mutex
29 | seqnum uint
30 | table map[uint]chan struct{}
31 | }
32 |
33 | var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})}
34 |
35 | func (t *unlock_notify_table) add(c chan struct{}) uint {
36 | t.Lock()
37 | defer t.Unlock()
38 | h := t.seqnum
39 | t.table[h] = c
40 | t.seqnum++
41 | return h
42 | }
43 |
44 | func (t *unlock_notify_table) remove(h uint) {
45 | t.Lock()
46 | defer t.Unlock()
47 | delete(t.table, h)
48 | }
49 |
50 | func (t *unlock_notify_table) get(h uint) chan struct{} {
51 | t.Lock()
52 | defer t.Unlock()
53 | c, ok := t.table[h]
54 | if !ok {
55 | panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h))
56 | }
57 | return c
58 | }
59 |
60 | //export unlock_notify_callback
61 | func unlock_notify_callback(argv unsafe.Pointer, argc C.int) {
62 | for i := 0; i < int(argc); i++ {
63 | parg := ((*(*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.uint)(nil))]*[1]uint)(argv))[i])
64 | arg := *parg
65 | h := arg[0]
66 | c := unt.get(h)
67 | c <- struct{}{}
68 | }
69 | }
70 |
71 | //export unlock_notify_wait
72 | func unlock_notify_wait(db *C.sqlite3) C.int {
73 | // It has to be a bufferred channel to not block in sqlite_unlock_notify
74 | // as sqlite_unlock_notify could invoke the callback before it returns.
75 | c := make(chan struct{}, 1)
76 | defer close(c)
77 |
78 | h := unt.add(c)
79 | defer unt.remove(h)
80 |
81 | pargv := C.malloc(C.sizeof_uint)
82 | defer C.free(pargv)
83 |
84 | argv := (*[1]uint)(pargv)
85 | argv[0] = h
86 | if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK {
87 | return rv
88 | }
89 |
90 | <-c
91 |
92 | return C.SQLITE_OK
93 | }
94 |
--------------------------------------------------------------------------------
/sqlite3_opt_unlock_notify_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build sqlite_unlock_notify
7 |
8 | package sqlite3
9 |
10 | import (
11 | "database/sql"
12 | "fmt"
13 | "os"
14 | "sync"
15 | "testing"
16 | "time"
17 | )
18 |
19 | func TestUnlockNotify(t *testing.T) {
20 | tempFilename := TempFilename(t)
21 | defer os.Remove(tempFilename)
22 | dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", tempFilename, 500)
23 | db, err := sql.Open("sqlite3", dsn)
24 | if err != nil {
25 | t.Fatal("Failed to open database:", err)
26 | }
27 | defer db.Close()
28 |
29 | _, err = db.Exec("CREATE TABLE foo(id INTEGER, status INTEGER)")
30 | if err != nil {
31 | t.Fatal("Failed to create table:", err)
32 | }
33 |
34 | tx, err := db.Begin()
35 | if err != nil {
36 | t.Fatal("Failed to begin transaction:", err)
37 | }
38 |
39 | _, err = tx.Exec("INSERT INTO foo(id, status) VALUES(1, 100)")
40 | if err != nil {
41 | t.Fatal("Failed to insert null:", err)
42 | }
43 |
44 | _, err = tx.Exec("UPDATE foo SET status = 200 WHERE id = 1")
45 | if err != nil {
46 | t.Fatal("Failed to update table:", err)
47 | }
48 |
49 | wg := sync.WaitGroup{}
50 | wg.Add(1)
51 | timer := time.NewTimer(500 * time.Millisecond)
52 | go func() {
53 | <-timer.C
54 | err := tx.Commit()
55 | if err != nil {
56 | t.Fatal("Failed to commit transaction:", err)
57 | }
58 | wg.Done()
59 | }()
60 |
61 | rows, err := db.Query("SELECT count(*) from foo")
62 | if err != nil {
63 | t.Fatal("Unable to query foo table:", err)
64 | }
65 |
66 | if rows.Next() {
67 | var count int
68 | if err := rows.Scan(&count); err != nil {
69 | t.Fatal("Failed to Scan rows", err)
70 | }
71 | }
72 | if err := rows.Err(); err != nil {
73 | t.Fatal("Failed at the call to Next:", err)
74 | }
75 | wg.Wait()
76 |
77 | }
78 |
79 | func TestUnlockNotifyMany(t *testing.T) {
80 | tempFilename := TempFilename(t)
81 | defer os.Remove(tempFilename)
82 | dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", tempFilename, 500)
83 | db, err := sql.Open("sqlite3", dsn)
84 | if err != nil {
85 | t.Fatal("Failed to open database:", err)
86 | }
87 | defer db.Close()
88 |
89 | _, err = db.Exec("CREATE TABLE foo(id INTEGER, status INTEGER)")
90 | if err != nil {
91 | t.Fatal("Failed to create table:", err)
92 | }
93 |
94 | tx, err := db.Begin()
95 | if err != nil {
96 | t.Fatal("Failed to begin transaction:", err)
97 | }
98 |
99 | _, err = tx.Exec("INSERT INTO foo(id, status) VALUES(1, 100)")
100 | if err != nil {
101 | t.Fatal("Failed to insert null:", err)
102 | }
103 |
104 | _, err = tx.Exec("UPDATE foo SET status = 200 WHERE id = 1")
105 | if err != nil {
106 | t.Fatal("Failed to update table:", err)
107 | }
108 |
109 | wg := sync.WaitGroup{}
110 | wg.Add(1)
111 | timer := time.NewTimer(500 * time.Millisecond)
112 | go func() {
113 | <-timer.C
114 | err := tx.Commit()
115 | if err != nil {
116 | t.Fatal("Failed to commit transaction:", err)
117 | }
118 | wg.Done()
119 | }()
120 |
121 | const concurrentQueries = 1000
122 | wg.Add(concurrentQueries)
123 | for i := 0; i < concurrentQueries; i++ {
124 | go func() {
125 | rows, err := db.Query("SELECT count(*) from foo")
126 | if err != nil {
127 | t.Fatal("Unable to query foo table:", err)
128 | }
129 |
130 | if rows.Next() {
131 | var count int
132 | if err := rows.Scan(&count); err != nil {
133 | t.Fatal("Failed to Scan rows", err)
134 | }
135 | }
136 | if err := rows.Err(); err != nil {
137 | t.Fatal("Failed at the call to Next:", err)
138 | }
139 | wg.Done()
140 | }()
141 | }
142 | wg.Wait()
143 | }
144 |
145 | func TestUnlockNotifyDeadlock(t *testing.T) {
146 | tempFilename := TempFilename(t)
147 | defer os.Remove(tempFilename)
148 | dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", tempFilename, 500)
149 | db, err := sql.Open("sqlite3", dsn)
150 | if err != nil {
151 | t.Fatal("Failed to open database:", err)
152 | }
153 | defer db.Close()
154 |
155 | _, err = db.Exec("CREATE TABLE foo(id INTEGER, status INTEGER)")
156 | if err != nil {
157 | t.Fatal("Failed to create table:", err)
158 | }
159 |
160 | tx, err := db.Begin()
161 | if err != nil {
162 | t.Fatal("Failed to begin transaction:", err)
163 | }
164 |
165 | _, err = tx.Exec("INSERT INTO foo(id, status) VALUES(1, 100)")
166 | if err != nil {
167 | t.Fatal("Failed to insert null:", err)
168 | }
169 |
170 | _, err = tx.Exec("UPDATE foo SET status = 200 WHERE id = 1")
171 | if err != nil {
172 | t.Fatal("Failed to update table:", err)
173 | }
174 |
175 | wg := sync.WaitGroup{}
176 | wg.Add(1)
177 | timer := time.NewTimer(500 * time.Millisecond)
178 | go func() {
179 | <-timer.C
180 | err := tx.Commit()
181 | if err != nil {
182 | t.Fatal("Failed to commit transaction:", err)
183 | }
184 | wg.Done()
185 | }()
186 |
187 | wg.Add(1)
188 | go func() {
189 | tx2, err := db.Begin()
190 | if err != nil {
191 | t.Fatal("Failed to begin transaction:", err)
192 | }
193 | defer tx2.Rollback()
194 |
195 | _, err = tx2.Exec("DELETE FROM foo")
196 | if err != nil {
197 | t.Fatal("Failed to delete table:", err)
198 | }
199 | err = tx2.Commit()
200 | if err != nil {
201 | t.Fatal("Failed to commit transaction:", err)
202 | }
203 | wg.Done()
204 | }()
205 |
206 | rows, err := tx.Query("SELECT count(*) from foo")
207 | if err != nil {
208 | t.Fatal("Unable to query foo table:", err)
209 | }
210 |
211 | if rows.Next() {
212 | var count int
213 | if err := rows.Scan(&count); err != nil {
214 | t.Fatal("Failed to Scan rows", err)
215 | }
216 | }
217 | if err := rows.Err(); err != nil {
218 | t.Fatal("Failed at the call to Next:", err)
219 | }
220 |
221 | wg.Wait()
222 | }
223 |
--------------------------------------------------------------------------------
/sqlite3_opt_userauth_omit.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 G.J.R. Timmer .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build !sqlite_userauth
7 |
8 | package sqlite3
9 |
10 | import (
11 | "C"
12 | )
13 |
14 | // Authenticate will perform an authentication of the provided username
15 | // and password against the database.
16 | //
17 | // If a database contains the SQLITE_USER table, then the
18 | // call to Authenticate must be invoked with an
19 | // appropriate username and password prior to enable read and write
20 | //access to the database.
21 | //
22 | // Return SQLITE_OK on success or SQLITE_ERROR if the username/password
23 | // combination is incorrect or unknown.
24 | //
25 | // If the SQLITE_USER table is not present in the database file, then
26 | // this interface is a harmless no-op returnning SQLITE_OK.
27 | func (c *SQLiteConn) Authenticate(username, password string) error {
28 | // NOOP
29 | return nil
30 | }
31 |
32 | // authenticate provides the actual authentication to SQLite.
33 | // This is not exported for usage in Go.
34 | // It is however exported for usage within SQL by the user.
35 | //
36 | // Returns:
37 | // C.SQLITE_OK (0)
38 | // C.SQLITE_ERROR (1)
39 | // C.SQLITE_AUTH (23)
40 | func (c *SQLiteConn) authenticate(username, password string) int {
41 | // NOOP
42 | return 0
43 | }
44 |
45 | // AuthUserAdd can be used (by an admin user only)
46 | // to create a new user. When called on a no-authentication-required
47 | // database, this routine converts the database into an authentication-
48 | // required database, automatically makes the added user an
49 | // administrator, and logs in the current connection as that user.
50 | // The AuthUserAdd only works for the "main" database, not
51 | // for any ATTACH-ed databases. Any call to AuthUserAdd by a
52 | // non-admin user results in an error.
53 | func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
54 | // NOOP
55 | return nil
56 | }
57 |
58 | // authUserAdd enables the User Authentication if not enabled.
59 | // Otherwise it will add a user.
60 | //
61 | // When user authentication is already enabled then this function
62 | // can only be called by an admin.
63 | //
64 | // This is not exported for usage in Go.
65 | // It is however exported for usage within SQL by the user.
66 | //
67 | // Returns:
68 | // C.SQLITE_OK (0)
69 | // C.SQLITE_ERROR (1)
70 | // C.SQLITE_AUTH (23)
71 | func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
72 | // NOOP
73 | return 0
74 | }
75 |
76 | // AuthUserChange can be used to change a users
77 | // login credentials or admin privilege. Any user can change their own
78 | // login credentials. Only an admin user can change another users login
79 | // credentials or admin privilege setting. No user may change their own
80 | // admin privilege setting.
81 | func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
82 | // NOOP
83 | return nil
84 | }
85 |
86 | // authUserChange allows to modify a user.
87 | // Users can change their own password.
88 | //
89 | // Only admins can change passwords for other users
90 | // and modify the admin flag.
91 | //
92 | // The admin flag of the current logged in user cannot be changed.
93 | // THis ensures that their is always an admin.
94 | //
95 | // This is not exported for usage in Go.
96 | // It is however exported for usage within SQL by the user.
97 | //
98 | // Returns:
99 | // C.SQLITE_OK (0)
100 | // C.SQLITE_ERROR (1)
101 | // C.SQLITE_AUTH (23)
102 | func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
103 | // NOOP
104 | return 0
105 | }
106 |
107 | // AuthUserDelete can be used (by an admin user only)
108 | // to delete a user. The currently logged-in user cannot be deleted,
109 | // which guarantees that there is always an admin user and hence that
110 | // the database cannot be converted into a no-authentication-required
111 | // database.
112 | func (c *SQLiteConn) AuthUserDelete(username string) error {
113 | // NOOP
114 | return nil
115 | }
116 |
117 | // authUserDelete can be used to delete a user.
118 | //
119 | // This function can only be executed by an admin.
120 | //
121 | // This is not exported for usage in Go.
122 | // It is however exported for usage within SQL by the user.
123 | //
124 | // Returns:
125 | // C.SQLITE_OK (0)
126 | // C.SQLITE_ERROR (1)
127 | // C.SQLITE_AUTH (23)
128 | func (c *SQLiteConn) authUserDelete(username string) int {
129 | // NOOP
130 | return 0
131 | }
132 |
133 | // AuthEnabled checks if the database is protected by user authentication
134 | func (c *SQLiteConn) AuthEnabled() (exists bool) {
135 | // NOOP
136 | return false
137 | }
138 |
139 | // authEnabled perform the actual check for user authentication.
140 | //
141 | // This is not exported for usage in Go.
142 | // It is however exported for usage within SQL by the user.
143 | //
144 | // Returns:
145 | // 0 - Disabled
146 | // 1 - Enabled
147 | func (c *SQLiteConn) authEnabled() int {
148 | // NOOP
149 | return 0
150 | }
151 |
152 | // EOF
153 |
--------------------------------------------------------------------------------
/sqlite3_opt_vacuum_full.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_vacuum_full
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=1
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_opt_vacuum_incr.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | // Copyright (C) 2018 G.J.R. Timmer .
3 | //
4 | // Use of this source code is governed by an MIT-style
5 | // license that can be found in the LICENSE file.
6 |
7 | // +build sqlite_vacuum_incr
8 |
9 | package sqlite3
10 |
11 | /*
12 | #cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=2
13 | #cgo LDFLAGS: -lm
14 | */
15 | import "C"
16 |
--------------------------------------------------------------------------------
/sqlite3_other.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build !windows
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -I.
12 | #cgo linux LDFLAGS: -ldl
13 | #cgo linux,ppc LDFLAGS: -lpthread
14 | #cgo linux,ppc64 LDFLAGS: -lpthread
15 | #cgo linux,ppc64le LDFLAGS: -lpthread
16 | */
17 | import "C"
18 |
--------------------------------------------------------------------------------
/sqlite3_solaris.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build solaris
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -D__EXTENSIONS__=1
12 | #cgo LDFLAGS: -lc
13 | */
14 | import "C"
15 |
--------------------------------------------------------------------------------
/sqlite3_type.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package sqlite3
7 |
8 | /*
9 | #ifndef USE_LIBSQLITE3
10 | #include
11 | #else
12 | #include
13 | #endif
14 | */
15 | import "C"
16 | import (
17 | "reflect"
18 | "time"
19 | )
20 |
21 | // ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName.
22 | func (rc *SQLiteRows) ColumnTypeDatabaseTypeName(i int) string {
23 | return C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))
24 | }
25 |
26 | /*
27 | func (rc *SQLiteRows) ColumnTypeLength(index int) (length int64, ok bool) {
28 | return 0, false
29 | }
30 |
31 | func (rc *SQLiteRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
32 | return 0, 0, false
33 | }
34 | */
35 |
36 | // ColumnTypeNullable implement RowsColumnTypeNullable.
37 | func (rc *SQLiteRows) ColumnTypeNullable(i int) (nullable, ok bool) {
38 | return true, true
39 | }
40 |
41 | // ColumnTypeScanType implement RowsColumnTypeScanType.
42 | func (rc *SQLiteRows) ColumnTypeScanType(i int) reflect.Type {
43 | switch C.sqlite3_column_type(rc.s.s, C.int(i)) {
44 | case C.SQLITE_INTEGER:
45 | switch C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) {
46 | case "timestamp", "datetime", "date":
47 | return reflect.TypeOf(time.Time{})
48 | case "boolean":
49 | return reflect.TypeOf(false)
50 | }
51 | return reflect.TypeOf(int64(0))
52 | case C.SQLITE_FLOAT:
53 | return reflect.TypeOf(float64(0))
54 | case C.SQLITE_BLOB:
55 | return reflect.SliceOf(reflect.TypeOf(byte(0)))
56 | case C.SQLITE_NULL:
57 | return reflect.TypeOf(nil)
58 | case C.SQLITE_TEXT:
59 | return reflect.TypeOf("")
60 | }
61 | return reflect.SliceOf(reflect.TypeOf(byte(0)))
62 | }
63 |
--------------------------------------------------------------------------------
/sqlite3_usleep_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2018 G.J.R. Timmer .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build cgo
7 |
8 | package sqlite3
9 |
10 | // usleep is a function available on *nix based systems.
11 | // This function is not present in Windows.
12 | // Windows has a sleep function but this works with seconds
13 | // and not with microseconds as usleep.
14 | //
15 | // This code should improve performance on windows because
16 | // without the presence of usleep SQLite waits 1 second.
17 | //
18 | // Source: https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
19 |
20 | /*
21 | #include
22 |
23 | void usleep(__int64 usec)
24 | {
25 | HANDLE timer;
26 | LARGE_INTEGER ft;
27 |
28 | // Convert to 100 nanosecond interval, negative value indicates relative time
29 | ft.QuadPart = -(10*usec);
30 |
31 | timer = CreateWaitableTimer(NULL, TRUE, NULL);
32 | SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
33 | WaitForSingleObject(timer, INFINITE);
34 | CloseHandle(timer);
35 | }
36 | */
37 | import "C"
38 |
39 | // EOF
40 |
--------------------------------------------------------------------------------
/sqlite3_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build windows
7 |
8 | package sqlite3
9 |
10 | /*
11 | #cgo CFLAGS: -I.
12 | #cgo CFLAGS: -fno-stack-check
13 | #cgo CFLAGS: -fno-stack-protector
14 | #cgo CFLAGS: -mno-stack-arg-probe
15 | #cgo LDFLAGS: -lmingwex -lmingw32
16 | #cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T
17 | */
18 | import "C"
19 |
--------------------------------------------------------------------------------
/static_mock.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2019 Yasuhiro Matsumoto .
2 | //
3 | // Use of this source code is governed by an MIT-style
4 | // license that can be found in the LICENSE file.
5 |
6 | // +build !cgo
7 |
8 | package sqlite3
9 |
10 | import (
11 | "database/sql"
12 | "database/sql/driver"
13 | "errors"
14 | )
15 |
16 | var errorMsg = errors.New("Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub")
17 |
18 | func init() {
19 | sql.Register("sqlite3", &SQLiteDriver{})
20 | }
21 |
22 | type (
23 | SQLiteDriver struct {
24 | Extensions []string
25 | ConnectHook func(*SQLiteConn) error
26 | }
27 | SQLiteConn struct{}
28 | )
29 |
30 | func (SQLiteDriver) Open(s string) (driver.Conn, error) { return nil, errorMsg }
31 | func (c *SQLiteConn) RegisterAggregator(string, interface{}, bool) error { return errorMsg }
32 | func (c *SQLiteConn) RegisterAuthorizer(func(int, string, string, string) int) {}
33 | func (c *SQLiteConn) RegisterCollation(string, func(string, string) int) error { return errorMsg }
34 | func (c *SQLiteConn) RegisterCommitHook(func() int) {}
35 | func (c *SQLiteConn) RegisterFunc(string, interface{}, bool) error { return errorMsg }
36 | func (c *SQLiteConn) RegisterRollbackHook(func()) {}
37 | func (c *SQLiteConn) RegisterUpdateHook(func(int, string, string, int64)) {}
38 |
--------------------------------------------------------------------------------
/testdata/sqlcipher3.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutecomm/go-sqlcipher/25f68adb9fb3bc95229bee7e3498a6ca2f3e752d/testdata/sqlcipher3.sqlite3
--------------------------------------------------------------------------------
/testdata/sqlcipher4.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutecomm/go-sqlcipher/25f68adb9fb3bc95229bee7e3498a6ca2f3e752d/testdata/sqlcipher4.sqlite3
--------------------------------------------------------------------------------
/tomcrypt.h:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 |
4 | #ifndef TOMCRYPT_H_
5 | #define TOMCRYPT_H_
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | /* use configuration data */
16 | #include "tomcrypt_custom.h"
17 |
18 | #ifdef __cplusplus
19 | extern "C" {
20 | #endif
21 |
22 | /* version */
23 | #define CRYPT 0x0118
24 | #define SCRYPT "1.18.2-develop"
25 |
26 | /* max size of either a cipher/hash block or symmetric key [largest of the two] */
27 | #define MAXBLOCKSIZE 144
28 |
29 | #ifndef TAB_SIZE
30 | /* descriptor table size */
31 | #define TAB_SIZE 34
32 | #endif
33 |
34 | /* error codes [will be expanded in future releases] */
35 | enum {
36 | CRYPT_OK=0, /* Result OK */
37 | CRYPT_ERROR, /* Generic Error */
38 | CRYPT_NOP, /* Not a failure but no operation was performed */
39 |
40 | CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
41 | CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
42 | CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
43 |
44 | CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
45 | CRYPT_INVALID_PACKET, /* Invalid input packet given */
46 |
47 | CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
48 | CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
49 |
50 | CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
51 | CRYPT_INVALID_HASH, /* Invalid hash specified */
52 | CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
53 |
54 | CRYPT_MEM, /* Out of memory */
55 |
56 | CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
57 | CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
58 |
59 | CRYPT_INVALID_ARG, /* Generic invalid argument */
60 | CRYPT_FILE_NOTFOUND, /* File Not Found */
61 |
62 | CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
63 |
64 | CRYPT_OVERFLOW, /* An overflow of a value was detected/prevented */
65 |
66 | CRYPT_PK_ASN1_ERROR, /* An error occurred while en- or decoding ASN.1 data */
67 |
68 | CRYPT_INPUT_TOO_LONG, /* The input was longer than expected. */
69 |
70 | CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
71 |
72 | CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
73 | CRYPT_PK_INVALID_PADDING, /* Invalid padding on input */
74 |
75 | CRYPT_HASH_OVERFLOW /* Hash applied to too many bits */
76 | };
77 |
78 | #include "tomcrypt_cfg.h"
79 | #include "tomcrypt_macros.h"
80 | #include "tomcrypt_cipher.h"
81 | #include "tomcrypt_hash.h"
82 | #include "tomcrypt_mac.h"
83 | #include "tomcrypt_prng.h"
84 | #include "tomcrypt_pk.h"
85 | #include "tomcrypt_math.h"
86 | #include "tomcrypt_misc.h"
87 | #include "tomcrypt_argchk.h"
88 | #include "tomcrypt_pkcs.h"
89 |
90 | #ifdef __cplusplus
91 | }
92 | #endif
93 |
94 | #endif /* TOMCRYPT_H_ */
95 |
96 |
--------------------------------------------------------------------------------
/tomcrypt_argchk.h:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 |
4 | /* Defines the LTC_ARGCHK macro used within the library */
5 | /* ARGTYPE is defined in tomcrypt_cfg.h */
6 |
7 | /* ARGTYPE is per default defined to 0 */
8 | #if ARGTYPE == 0
9 |
10 | #include
11 |
12 | LTC_NORETURN void crypt_argchk(const char *v, const char *s, int d);
13 | #define LTC_ARGCHK(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0)
14 | #define LTC_ARGCHKVD(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0)
15 |
16 | #elif ARGTYPE == 1
17 |
18 | /* fatal type of error */
19 | #define LTC_ARGCHK(x) assert((x))
20 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
21 |
22 | #elif ARGTYPE == 2
23 |
24 | #define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
25 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
26 |
27 | #elif ARGTYPE == 3
28 |
29 | #define LTC_ARGCHK(x) LTC_UNUSED_PARAM(x)
30 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
31 |
32 | #elif ARGTYPE == 4
33 |
34 | #define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG;
35 | #define LTC_ARGCHKVD(x) if (!(x)) return;
36 |
37 | #endif
38 |
39 |
--------------------------------------------------------------------------------
/tomcrypt_misc.h:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 |
4 | /* ---- LTC_BASE64 Routines ---- */
5 | #ifdef LTC_BASE64
6 | int base64_encode(const unsigned char *in, unsigned long inlen,
7 | char *out, unsigned long *outlen);
8 |
9 | int base64_decode(const char *in, unsigned long inlen,
10 | unsigned char *out, unsigned long *outlen);
11 | int base64_strict_decode(const char *in, unsigned long inlen,
12 | unsigned char *out, unsigned long *outlen);
13 | int base64_sane_decode(const char *in, unsigned long inlen,
14 | unsigned char *out, unsigned long *outlen);
15 | #endif
16 |
17 | #ifdef LTC_BASE64_URL
18 | int base64url_encode(const unsigned char *in, unsigned long inlen,
19 | char *out, unsigned long *outlen);
20 | int base64url_strict_encode(const unsigned char *in, unsigned long inlen,
21 | char *out, unsigned long *outlen);
22 |
23 | int base64url_decode(const char *in, unsigned long inlen,
24 | unsigned char *out, unsigned long *outlen);
25 | int base64url_strict_decode(const char *in, unsigned long inlen,
26 | unsigned char *out, unsigned long *outlen);
27 | int base64url_sane_decode(const char *in, unsigned long inlen,
28 | unsigned char *out, unsigned long *outlen);
29 | #endif
30 |
31 | /* ---- BASE32 Routines ---- */
32 | #ifdef LTC_BASE32
33 | typedef enum {
34 | BASE32_RFC4648 = 0,
35 | BASE32_BASE32HEX = 1,
36 | BASE32_ZBASE32 = 2,
37 | BASE32_CROCKFORD = 3
38 | } base32_alphabet;
39 | int base32_encode(const unsigned char *in, unsigned long inlen,
40 | char *out, unsigned long *outlen,
41 | base32_alphabet id);
42 | int base32_decode(const char *in, unsigned long inlen,
43 | unsigned char *out, unsigned long *outlen,
44 | base32_alphabet id);
45 | #endif
46 |
47 | /* ---- BASE16 Routines ---- */
48 | #ifdef LTC_BASE16
49 | int base16_encode(const unsigned char *in, unsigned long inlen,
50 | char *out, unsigned long *outlen,
51 | unsigned int options);
52 | int base16_decode(const char *in, unsigned long inlen,
53 | unsigned char *out, unsigned long *outlen);
54 | #endif
55 |
56 | #ifdef LTC_BCRYPT
57 | int bcrypt_pbkdf_openbsd(const void *secret, unsigned long secret_len,
58 | const unsigned char *salt, unsigned long salt_len,
59 | unsigned int rounds, int hash_idx,
60 | unsigned char *out, unsigned long *outlen);
61 | #endif
62 |
63 | /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
64 | #ifdef LTC_HKDF
65 |
66 | int hkdf_test(void);
67 |
68 | int hkdf_extract(int hash_idx,
69 | const unsigned char *salt, unsigned long saltlen,
70 | const unsigned char *in, unsigned long inlen,
71 | unsigned char *out, unsigned long *outlen);
72 |
73 | int hkdf_expand(int hash_idx,
74 | const unsigned char *info, unsigned long infolen,
75 | const unsigned char *in, unsigned long inlen,
76 | unsigned char *out, unsigned long outlen);
77 |
78 | int hkdf(int hash_idx,
79 | const unsigned char *salt, unsigned long saltlen,
80 | const unsigned char *info, unsigned long infolen,
81 | const unsigned char *in, unsigned long inlen,
82 | unsigned char *out, unsigned long outlen);
83 |
84 | #endif /* LTC_HKDF */
85 |
86 | /* ---- MEM routines ---- */
87 | int mem_neq(const void *a, const void *b, size_t len);
88 | void zeromem(volatile void *out, size_t outlen);
89 | void burn_stack(unsigned long len);
90 |
91 | const char *error_to_string(int err);
92 |
93 | extern const char *crypt_build_settings;
94 |
95 | /* ---- HMM ---- */
96 | int crypt_fsa(void *mp, ...);
97 |
98 | /* ---- Dynamic language support ---- */
99 | int crypt_get_constant(const char* namein, int *valueout);
100 | int crypt_list_all_constants(char *names_list, unsigned int *names_list_size);
101 |
102 | int crypt_get_size(const char* namein, unsigned int *sizeout);
103 | int crypt_list_all_sizes(char *names_list, unsigned int *names_list_size);
104 |
105 | #ifdef LTM_DESC
106 | LTC_DEPRECATED(crypt_mp_init) void init_LTM(void);
107 | #endif
108 | #ifdef TFM_DESC
109 | LTC_DEPRECATED(crypt_mp_init) void init_TFM(void);
110 | #endif
111 | #ifdef GMP_DESC
112 | LTC_DEPRECATED(crypt_mp_init) void init_GMP(void);
113 | #endif
114 | int crypt_mp_init(const char* mpi);
115 |
116 | #ifdef LTC_ADLER32
117 | typedef struct adler32_state_s
118 | {
119 | unsigned short s[2];
120 | } adler32_state;
121 |
122 | void adler32_init(adler32_state *ctx);
123 | void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length);
124 | void adler32_finish(const adler32_state *ctx, void *hash, unsigned long size);
125 | int adler32_test(void);
126 | #endif
127 |
128 | #ifdef LTC_CRC32
129 | typedef struct crc32_state_s
130 | {
131 | ulong32 crc;
132 | } crc32_state;
133 |
134 | void crc32_init(crc32_state *ctx);
135 | void crc32_update(crc32_state *ctx, const unsigned char *input, unsigned long length);
136 | void crc32_finish(const crc32_state *ctx, void *hash, unsigned long size);
137 | int crc32_test(void);
138 | #endif
139 |
140 |
141 | #ifdef LTC_PADDING
142 |
143 | enum padding_type {
144 | LTC_PAD_PKCS7 = 0x0000U,
145 | #ifdef LTC_RNG_GET_BYTES
146 | LTC_PAD_ISO_10126 = 0x1000U,
147 | #endif
148 | LTC_PAD_ANSI_X923 = 0x2000U,
149 | LTC_PAD_ONE_AND_ZERO = 0x8000U,
150 | LTC_PAD_ZERO = 0x9000U,
151 | LTC_PAD_ZERO_ALWAYS = 0xA000U,
152 | };
153 |
154 | int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded_length, unsigned long mode);
155 | int padding_depad(const unsigned char *data, unsigned long *length, unsigned long mode);
156 | #endif /* LTC_PADDING */
157 |
158 | #ifdef LTC_SSH
159 | typedef enum ssh_data_type_ {
160 | LTC_SSHDATA_EOL,
161 | LTC_SSHDATA_BYTE,
162 | LTC_SSHDATA_BOOLEAN,
163 | LTC_SSHDATA_UINT32,
164 | LTC_SSHDATA_UINT64,
165 | LTC_SSHDATA_STRING,
166 | LTC_SSHDATA_MPINT,
167 | LTC_SSHDATA_NAMELIST,
168 | } ssh_data_type;
169 |
170 | /* VA list handy helpers with tuples of */
171 | int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
172 | int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...);
173 | #endif /* LTC_SSH */
174 |
175 | int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);
176 |
--------------------------------------------------------------------------------
/tomcrypt_pkcs.h:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 |
4 | /* PKCS Header Info */
5 |
6 | /* ===> PKCS #1 -- RSA Cryptography <=== */
7 | #ifdef LTC_PKCS_1
8 |
9 | enum ltc_pkcs_1_v1_5_blocks
10 | {
11 | LTC_PKCS_1_EMSA = 1, /* Block type 1 (PKCS #1 v1.5 signature padding) */
12 | LTC_PKCS_1_EME = 2 /* Block type 2 (PKCS #1 v1.5 encryption padding) */
13 | };
14 |
15 | enum ltc_pkcs_1_paddings
16 | {
17 | LTC_PKCS_1_V1_5 = 1, /* PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
18 | LTC_PKCS_1_OAEP = 2, /* PKCS #1 v2.0 encryption padding */
19 | LTC_PKCS_1_PSS = 3, /* PKCS #1 v2.1 signature padding */
20 | LTC_PKCS_1_V1_5_NA1 = 4 /* PKCS #1 v1.5 padding - No ASN.1 (\sa ltc_pkcs_1_v1_5_blocks) */
21 | };
22 |
23 | int pkcs_1_mgf1( int hash_idx,
24 | const unsigned char *seed, unsigned long seedlen,
25 | unsigned char *mask, unsigned long masklen);
26 |
27 | int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
28 | int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
29 |
30 | /* *** v1.5 padding */
31 | int pkcs_1_v1_5_encode(const unsigned char *msg,
32 | unsigned long msglen,
33 | int block_type,
34 | unsigned long modulus_bitlen,
35 | prng_state *prng,
36 | int prng_idx,
37 | unsigned char *out,
38 | unsigned long *outlen);
39 |
40 | int pkcs_1_v1_5_decode(const unsigned char *msg,
41 | unsigned long msglen,
42 | int block_type,
43 | unsigned long modulus_bitlen,
44 | unsigned char *out,
45 | unsigned long *outlen,
46 | int *is_valid);
47 |
48 | /* *** v2.1 padding */
49 | int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
50 | const unsigned char *lparam, unsigned long lparamlen,
51 | unsigned long modulus_bitlen, prng_state *prng,
52 | int prng_idx, int hash_idx,
53 | unsigned char *out, unsigned long *outlen);
54 |
55 | int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
56 | const unsigned char *lparam, unsigned long lparamlen,
57 | unsigned long modulus_bitlen, int hash_idx,
58 | unsigned char *out, unsigned long *outlen,
59 | int *res);
60 |
61 | int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
62 | unsigned long saltlen, prng_state *prng,
63 | int prng_idx, int hash_idx,
64 | unsigned long modulus_bitlen,
65 | unsigned char *out, unsigned long *outlen);
66 |
67 | int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
68 | const unsigned char *sig, unsigned long siglen,
69 | unsigned long saltlen, int hash_idx,
70 | unsigned long modulus_bitlen, int *res);
71 |
72 | #endif /* LTC_PKCS_1 */
73 |
74 | /* ===> PKCS #5 -- Password Based Cryptography <=== */
75 | #ifdef LTC_PKCS_5
76 |
77 | /* Algorithm #1 (PBKDF1) */
78 | int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
79 | const unsigned char *salt,
80 | int iteration_count, int hash_idx,
81 | unsigned char *out, unsigned long *outlen);
82 |
83 | /* Algorithm #1 (PBKDF1) - OpenSSL-compatible variant for arbitrarily-long keys.
84 | Compatible with EVP_BytesToKey() */
85 | int pkcs_5_alg1_openssl(const unsigned char *password,
86 | unsigned long password_len,
87 | const unsigned char *salt,
88 | int iteration_count, int hash_idx,
89 | unsigned char *out, unsigned long *outlen);
90 |
91 | /* Algorithm #2 (PBKDF2) */
92 | int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
93 | const unsigned char *salt, unsigned long salt_len,
94 | int iteration_count, int hash_idx,
95 | unsigned char *out, unsigned long *outlen);
96 |
97 | int pkcs_5_test (void);
98 | #endif /* LTC_PKCS_5 */
99 |
100 |
--------------------------------------------------------------------------------
/track_go-sqlite3.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | if [ $# -ne 1 ]
4 | then
5 | echo "Usage: $0 go-sqlite3_dir" >&2
6 | echo "Copy tracked source files from go-sqlite3 to current directory." >&2
7 | exit 1
8 | fi
9 |
10 | ltd=$1
11 |
12 | # copy C files
13 | cp -f $ltd/sqlite3_opt_unlock_notify.c .
14 |
15 | # copy Go files
16 | cp -f $ltd/*.go .
17 | rm -rf _example
18 | cp -r $ltd/_example .
19 | rm -rf upgrade
20 | cp -r $ltd/upgrade .
21 |
22 | echo "make sure to adjust sqlite3.go with sqlcipher pragmas!"
23 | echo "make sure to adjust import paths in _example directory!"
24 |
--------------------------------------------------------------------------------
/track_libtomcrypt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | if [ $# -ne 1 ]
4 | then
5 | echo "Usage: $0 libtomcrypt_dir" >&2
6 | echo "Copy tracked source files from libtomcrypt_dir to current directory." >&2
7 | exit 1
8 | fi
9 |
10 | ltd=$1
11 |
12 | # copy header files
13 | cp -f $ltd/src/headers/tomcrypt_argchk.h .
14 | cp -f $ltd/src/headers/tomcrypt_cfg.h .
15 | cp -f $ltd/src/headers/tomcrypt_cipher.h .
16 | cp -f $ltd/src/headers/tomcrypt_custom.h .
17 | cp -f $ltd/src/headers/tomcrypt.h .
18 | cp -f $ltd/src/headers/tomcrypt_hash.h .
19 | cp -f $ltd/src/headers/tomcrypt_mac.h .
20 | cp -f $ltd/src/headers/tomcrypt_macros.h .
21 | cp -f $ltd/src/headers/tomcrypt_math.h .
22 | cp -f $ltd/src/headers/tomcrypt_misc.h .
23 | cp -f $ltd/src/headers/tomcrypt_pkcs.h .
24 | cp -f $ltd/src/headers/tomcrypt_pk.h .
25 | cp -f $ltd/src/headers/tomcrypt_private.h .
26 | cp -f $ltd/src/headers/tomcrypt_prng.h .
27 |
28 | # copy C files
29 | cp -f $ltd/src/ciphers/aes/aes.c .
30 | cp -f $ltd/src/ciphers/aes/aes_tab.c aes_tab.h
31 | cp -f $ltd/src/misc/burn_stack.c .
32 | cp -f $ltd/src/misc/compare_testvector.c .
33 | cp -f $ltd/src/modes/cbc/cbc_decrypt.c .
34 | cp -f $ltd/src/modes/cbc/cbc_done.c .
35 | cp -f $ltd/src/modes/cbc/cbc_encrypt.c .
36 | cp -f $ltd/src/modes/cbc/cbc_start.c .
37 | cp -f $ltd/src/misc/crypt/crypt_argchk.c .
38 | cp -f $ltd/src/misc/crypt/crypt_cipher_descriptor.c .
39 | cp -f $ltd/src/misc/crypt/crypt_cipher_is_valid.c .
40 | cp -f $ltd/src/misc/crypt/crypt_find_cipher.c .
41 | cp -f $ltd/src/misc/crypt/crypt_find_hash.c .
42 | cp -f $ltd/src/misc/crypt/crypt_hash_descriptor.c .
43 | cp -f $ltd/src/misc/crypt/crypt_hash_is_valid.c .
44 | cp -f $ltd/src/misc/crypt/crypt_prng_descriptor.c .
45 | cp -f $ltd/src/misc/crypt/crypt_register_cipher.c .
46 | cp -f $ltd/src/misc/crypt/crypt_register_hash.c .
47 | cp -f $ltd/src/misc/crypt/crypt_register_prng.c .
48 | cp -f $ltd/src/prngs/fortuna.c .
49 | cp -f $ltd/src/hashes/helper/hash_memory.c .
50 | cp -f $ltd/src/mac/hmac/hmac_done.c .
51 | cp -f $ltd/src/mac/hmac/hmac_init.c .
52 | cp -f $ltd/src/mac/hmac/hmac_memory.c .
53 | cp -f $ltd/src/mac/hmac/hmac_process.c .
54 | cp -f $ltd/src/misc/pkcs5/pkcs_5_2.c .
55 | cp -f $ltd/src/hashes/sha1.c .
56 | cp -f $ltd/src/hashes/sha2/sha256.c .
57 | cp -f $ltd/src/hashes/sha2/sha512.c .
58 | cp -f $ltd/src/misc/zeromem.c .
59 |
60 | echo "make sure aes.c includes aes_tab.h instead of aes_tab.c!"
61 |
--------------------------------------------------------------------------------
/upgrade/package.go:
--------------------------------------------------------------------------------
1 | // Package upgrade is a dummy package to ensure package can be loaded
2 | //
3 | // This file is to avoid the following error:
4 | // can't load package: package go-sqlite3/upgrade: build constraints exclude all Go files in go-sqlite3\upgrade
5 | package upgrade
6 |
--------------------------------------------------------------------------------
/upgrade/upgrade.go:
--------------------------------------------------------------------------------
1 | // +build !cgo
2 | // +build upgrade,ignore
3 |
4 | package main
5 |
6 | import (
7 | "archive/zip"
8 | "bufio"
9 | "bytes"
10 | "fmt"
11 | "io"
12 | "io/ioutil"
13 | "log"
14 | "net/http"
15 | "os"
16 | "path"
17 | "path/filepath"
18 | "strings"
19 | "time"
20 |
21 | "github.com/PuerkitoBio/goquery"
22 | )
23 |
24 | func download(prefix string) (url string, content []byte, err error) {
25 | year := time.Now().Year()
26 |
27 | site := "https://www.sqlite.org/download.html"
28 | //fmt.Printf("scraping %v\n", site)
29 | doc, err := goquery.NewDocument(site)
30 | if err != nil {
31 | log.Fatal(err)
32 | }
33 |
34 | doc.Find("a").Each(func(_ int, s *goquery.Selection) {
35 | if strings.HasPrefix(s.Text(), prefix) {
36 | url = fmt.Sprintf("https://www.sqlite.org/%d/", year) + s.Text()
37 | }
38 | })
39 |
40 | if url == "" {
41 | return "", nil, fmt.Errorf("Unable to find prefix '%s' on sqlite.org", prefix)
42 | }
43 |
44 | fmt.Printf("Downloading %v\n", url)
45 | resp, err := http.Get(url)
46 | if err != nil {
47 | log.Fatal(err)
48 | }
49 |
50 | // Ready Body Content
51 | content, err = ioutil.ReadAll(resp.Body)
52 | defer resp.Body.Close()
53 | if err != nil {
54 | return "", nil, err
55 | }
56 |
57 | return url, content, nil
58 | }
59 |
60 | func mergeFile(src string, dst string) error {
61 | defer func() error {
62 | fmt.Printf("Removing: %s\n", src)
63 | err := os.Remove(src)
64 |
65 | if err != nil {
66 | return err
67 | }
68 |
69 | return nil
70 | }()
71 |
72 | // Open destination
73 | fdst, err := os.OpenFile(dst, os.O_APPEND|os.O_WRONLY, 0666)
74 | if err != nil {
75 | return err
76 | }
77 | defer fdst.Close()
78 |
79 | // Read source content
80 | content, err := ioutil.ReadFile(src)
81 | if err != nil {
82 | return err
83 | }
84 |
85 | // Add Additional newline
86 | if _, err := fdst.WriteString("\n"); err != nil {
87 | return err
88 | }
89 |
90 | fmt.Printf("Merging: %s into %s\n", src, dst)
91 | if _, err = fdst.Write(content); err != nil {
92 | return err
93 | }
94 |
95 | return nil
96 | }
97 |
98 | func main() {
99 | fmt.Println("Go-SQLite3 Upgrade Tool")
100 |
101 | // Download Amalgamation
102 | _, amalgamation, err := download("sqlite-amalgamation-")
103 | if err != nil {
104 | fmt.Println("Failed to download: sqlite-amalgamation; %s", err)
105 | }
106 |
107 | // Download Source
108 | _, source, err := download("sqlite-src-")
109 | if err != nil {
110 | fmt.Println("Failed to download: sqlite-src; %s", err)
111 | }
112 |
113 | // Create Amalgamation Zip Reader
114 | rAmalgamation, err := zip.NewReader(bytes.NewReader(amalgamation), int64(len(amalgamation)))
115 | if err != nil {
116 | log.Fatal(err)
117 | }
118 |
119 | // Create Source Zip Reader
120 | rSource, err := zip.NewReader(bytes.NewReader(source), int64(len(source)))
121 | if err != nil {
122 | log.Fatal(err)
123 | }
124 |
125 | // Extract Amalgamation
126 | for _, zf := range rAmalgamation.File {
127 | var f *os.File
128 | switch path.Base(zf.Name) {
129 | case "sqlite3.c":
130 | f, err = os.Create("sqlite3-binding.c")
131 | case "sqlite3.h":
132 | f, err = os.Create("sqlite3-binding.h")
133 | case "sqlite3ext.h":
134 | f, err = os.Create("sqlite3ext.h")
135 | default:
136 | continue
137 | }
138 | if err != nil {
139 | log.Fatal(err)
140 | }
141 | zr, err := zf.Open()
142 | if err != nil {
143 | log.Fatal(err)
144 | }
145 |
146 | _, err = io.WriteString(f, "#ifndef USE_LIBSQLITE3\n")
147 | if err != nil {
148 | zr.Close()
149 | f.Close()
150 | log.Fatal(err)
151 | }
152 | scanner := bufio.NewScanner(zr)
153 | for scanner.Scan() {
154 | text := scanner.Text()
155 | if text == `#include "sqlite3.h"` {
156 | text = `#include "sqlite3-binding.h"`
157 | }
158 | _, err = fmt.Fprintln(f, text)
159 | if err != nil {
160 | break
161 | }
162 | }
163 | err = scanner.Err()
164 | if err != nil {
165 | zr.Close()
166 | f.Close()
167 | log.Fatal(err)
168 | }
169 | _, err = io.WriteString(f, "#else // USE_LIBSQLITE3\n // If users really want to link against the system sqlite3 we\n// need to make this file a noop.\n #endif")
170 | if err != nil {
171 | zr.Close()
172 | f.Close()
173 | log.Fatal(err)
174 | }
175 | zr.Close()
176 | f.Close()
177 | fmt.Printf("Extracted: %v\n", filepath.Base(f.Name()))
178 | }
179 |
180 | //Extract Source
181 | for _, zf := range rSource.File {
182 | var f *os.File
183 | switch path.Base(zf.Name) {
184 | case "userauth.c":
185 | f, err = os.Create("userauth.c")
186 | case "sqlite3userauth.h":
187 | f, err = os.Create("userauth.h")
188 | default:
189 | continue
190 | }
191 | if err != nil {
192 | log.Fatal(err)
193 | }
194 | zr, err := zf.Open()
195 | if err != nil {
196 | log.Fatal(err)
197 | }
198 |
199 | _, err = io.Copy(f, zr)
200 | if err != nil {
201 | log.Fatal(err)
202 | }
203 |
204 | zr.Close()
205 | f.Close()
206 | fmt.Printf("extracted %v\n", filepath.Base(f.Name()))
207 | }
208 |
209 | // Merge SQLite User Authentication into amalgamation
210 | if err := mergeFile("userauth.c", "sqlite3-binding.c"); err != nil {
211 | log.Fatal(err)
212 | }
213 | if err := mergeFile("userauth.h", "sqlite3-binding.h"); err != nil {
214 | log.Fatal(err)
215 | }
216 |
217 | os.Exit(0)
218 | }
219 |
--------------------------------------------------------------------------------
/util/create/create.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "net/url"
7 | "os"
8 |
9 | _ "github.com/mutecomm/go-sqlcipher/v4"
10 | )
11 |
12 | func create(dbname, password string) error {
13 | dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s&_pragma_cipher_page_size=4096", url.QueryEscape(password))
14 | db, err := sql.Open("sqlite3", dbnameWithDSN)
15 | if err != nil {
16 | return err
17 | }
18 | defer db.Close()
19 | _, err = db.Exec("CREATE TABLE t1(a,b);")
20 | if err != nil {
21 | return err
22 | }
23 | _, err = db.Exec("INSERT INTO t1(a,b) values('one for the money', 'two for the show');")
24 | return err
25 | }
26 |
27 | func fatal(err error) {
28 | fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err)
29 | os.Exit(1)
30 | }
31 |
32 | func usage() {
33 | fmt.Fprintf(os.Stderr, "usage: %s db_file password\n", os.Args[0])
34 | os.Exit(2)
35 | }
36 |
37 | func main() {
38 | if len(os.Args) != 3 {
39 | usage()
40 | }
41 | if err := create(os.Args[1], os.Args[2]); err != nil {
42 | fatal(err)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/util/select/select.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "net/url"
7 | "os"
8 |
9 | _ "github.com/mutecomm/go-sqlcipher/v4"
10 | )
11 |
12 | func selectFromDB(dbname, password string) error {
13 | dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s&_pragma_cipher_page_size=4096", url.QueryEscape(password))
14 | db, err := sql.Open("sqlite3", dbnameWithDSN)
15 | if err != nil {
16 | return err
17 | }
18 | defer db.Close()
19 | var a, b string
20 | row := db.QueryRow("SELECT * FROM t1;")
21 | err = row.Scan(&a, &b)
22 | if err != nil {
23 | return err
24 | }
25 | fmt.Printf("%s, %s\n", a, b)
26 | return nil
27 | }
28 |
29 | func fatal(err error) {
30 | fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err)
31 | os.Exit(1)
32 | }
33 |
34 | func usage() {
35 | fmt.Fprintf(os.Stderr, "usage: %s db_file password\n", os.Args[0])
36 | os.Exit(2)
37 | }
38 |
39 | func main() {
40 | if len(os.Args) != 3 {
41 | usage()
42 | }
43 | if err := selectFromDB(os.Args[1], os.Args[2]); err != nil {
44 | fatal(err)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/zeromem.c:
--------------------------------------------------------------------------------
1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 | /* SPDX-License-Identifier: Unlicense */
3 | #include "tomcrypt_private.h"
4 |
5 | /**
6 | @file zeromem.c
7 | Zero a block of memory, Tom St Denis
8 | */
9 |
10 | /**
11 | Zero a block of memory
12 | @param out The destination of the area to zero
13 | @param outlen The length of the area to zero (octets)
14 | */
15 | void zeromem(volatile void *out, size_t outlen)
16 | {
17 | volatile char *mem = out;
18 | LTC_ARGCHKVD(out != NULL);
19 | while (outlen-- > 0) {
20 | *mem++ = '\0';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------