├── .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 | [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/mutecomm/go-sqlcipher) [![CI](https://github.com/mutecomm/go-sqlcipher/workflows/CI/badge.svg)](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 | --------------------------------------------------------------------------------