亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Go和Gorm實現(xiàn)讀取SQLCipher加密數(shù)據(jù)庫

 更新時間:2024年06月14日 10:06:01   作者:非曉為驍  
本文檔主要描述通過Go和Gorm實現(xiàn)生成和讀取SQLCipher加密數(shù)據(jù)庫以及其中踩的一些坑,文章通過代碼示例講解的非常詳細, 對大家的學習或工作有一定的幫助,需要的朋友可以參考下

本文檔主要描述通過 https://github.com/mutecomm/go-sqlcipher 生成和讀取 SQLCipher 加密數(shù)據(jù)庫以及其中踩的一些坑

軟件版本

go: v1.22.2

sqlcipher cli(ubuntun):3.15.2

sqlcipher(used for encrypt):v3

go-sqlcipher-package:https://github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f

Go 生成和讀取 SQLCipher 數(shù)據(jù)庫

生成數(shù)據(jù)庫

創(chuàng)建一個名為 encrypt-data.db,表為 test 的數(shù)據(jù)庫

import _ "github.com/mutecomm/go-sqlcipher"
func NewSQLCipherDB() {
    var (
		db      *sql.DB
		testDir = "go-sqlcipher_test"
		tables  = `CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT);`
		data    = `INSERT INTO test (data) VALUES ('Hello, World!');`
	)

	// create DB
	key := "passphrase"
	tmpdir, err := os.MkdirTemp("", testDir)
	if err != nil {
		panic(err)
	}
	dbname := filepath.Join(tmpdir, "encrypt-data.db")
	dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s", key)

	if db, err = sql.Open("sqlite3", dbnameWithDSN); err != nil {
		panic(err)
	}
    
    defer db.Close()

	if _, err = db.Exec(tables); err != nil {
		panic(err)
	}

	if _, err = db.Exec(data); err != nil {
		panic(err)
	}
    
	return
}

判斷數(shù)據(jù)庫是否加密

import sqlite3 "github.com/mutecomm/go-sqlcipher"

func IsSQLCipherEncrypted(dbName string) {
    // make sure DB is encrypted
	encrypted, err := sqlite3.IsEncrypted(dbName)
	if err != nil {
		panic(err)
	}
	if !encrypted {
		panic(errors.New("go-sqlcipher: DB not encrypted"))
	}
    
    fmt.Println("encrypted")
} 

讀取數(shù)據(jù)庫

import _ "github.com/mutecomm/go-sqlcipher"
func QuerySQLCipherDB(dbPath,key string) {
    var (
		db  *sql.DB
        err error
	)

	dbnameWithDSN := dbPath + fmt.Sprintf("?_pragma_key=%s", key)

	// open DB for testing
	db, err = sql.Open("sqlite3", dbnameWithDSN)
	if err != nil {
		panic(err)
	}
	_, err = db.Exec("SELECT count(*) FROM test;")
	if err != nil {
		panic(err)
	}
    
	return
}

如果密碼錯誤或者是數(shù)據(jù)庫錯誤,Line 15 會報 err

Gorm 連接 SQLCipher 數(shù)據(jù)庫

用原生方式讀取肯定不方便,所以還是找了一下如何用 gorm 來連接并讀取。其實這個 go-sqlcipher 就是一個驅(qū)動,所以跟 gorm 讀取 mysql 數(shù)據(jù)庫是差不多的。就是要注意把 “github.com/mutecomm/go-sqlcipher” import 進去。

import 	_ "github.com/mutecomm/go-sqlcipher"

var (
	db *gorm.DB
)

func Init(dbPath string) (err error) {
    key := "passphrase"
	dbPath = fmt.Sprintf(dbPath+"?_pragma_key=%s", key)

	db, err = gorm.Open("sqlite3", dbPath)
	if err != nil {
		return err
	}

	// logger Open
	db.LogMode(true)
	// Set Idle
	db.DB().SetMaxIdleConns(10)
    
    return nil
}

可視化工具讀取 SQLCipher 加密數(shù)據(jù)庫(1)

本篇下面的描述內(nèi)容主要是,因為創(chuàng)建加密數(shù)據(jù)庫參數(shù)出入,而要去修改可視化工具的一些參數(shù),具體見下文。

踩坑 & 分析

上述的方式都是基礎的,也正常是應該這么創(chuàng)建以及讀取的,但是我接手到的代碼是長下面這樣子的。

key := "passphrase"
dbPath = fmt.Sprintf(dbPath+"?_pragma_key=x'%s'&_pragma_cipher_page_size=4096", key)

db, err = gorm.Open("sqlite3", dbPath)
if err != nil {
	return err
}

奇奇怪怪的事情就開始發(fā)生了,用最基礎的 sqlcipher 指令讀取都會說密碼錯誤。

sqlcipher 密碼錯誤

sqlite> PRAGMA key = x'passphrase'; # 格式錯誤
sqlite> PRAGMA key = '70617373706872617365'; # passphrase hex 之后,密碼錯誤
sqlite> PRAGMA key = '78277061737370687261736527'; # x'passphrase' hex 之后,密碼錯誤
sqlite> PRAGMA key = "x'passphrase'";

先透露,第四個才是對的

按正常情況來看,應該這樣就可以正常讀取了,還是報密碼錯誤。

db browser 密碼錯誤

之前沒碰過這個,覺得 sqlcipher 是不是我不會,所以找了這個工具。

不過按照流程輸入密碼,也還是進不去,也選擇了 SQLCipher 3 也不行。

這邊 algorithm 跟源碼 README 里面的 AES 256 對不上,我以為是 db browser 不支持我這種加密格式

跑單測

按照別人給的不行,就從頭開始,自己創(chuàng)建,自己測試。

  • go 代碼創(chuàng)建加密數(shù)據(jù)庫,sqlcipher 指令讀取,這個是可以的。這一個測試我用的是最上面生成數(shù)據(jù)庫的代碼。
  • 因為我收到的代碼里面有帶,_pragma_cipher_page_size=4096。然后用這個方式創(chuàng)建的就是不行,以為我輸入的 key 是不是在第三方包內(nèi)有做什么動作,所以去分析了源碼庫。

跑完單元測試,說明密碼的輸入沒錯,就是這個 page size 的問題。

此時我還沒意識到是 page size 默認配置的問題

查源碼

以下源碼的 README,看得我迷糊,以為還要再 hex,多測了不同的加密方式也不行。

To create and open encrypted database files use the following DSN parameters:

key := "2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99"
dbname := fmt.Sprintf("db?_pragma_key=x'%s'&_pragma_cipher_page_size=4096", key)
db, _ := sql.Open("sqlite3", dbname)

_pragma_key is the hex encoded 32 byte key (must be 64 characters long). _pragma_cipher_page_size is the page size of the encrypted database (set if you want a different value than the default size).

key := url.QueryEscape("secret")
dbname := fmt.Sprintf("db?_pragma_key=%s&_pragma_cipher_page_size=4096", key)
db, _ := sql.Open("sqlite3", dbname)

This uses a passphrase directly as _pragma_key with the key derivation function in SQLCipher. Do not forget the url.QueryEscape() call in your code!

找 ISSUE

https://github.com/mutecomm/go-sqlcipher/issues/15

這個 issue 是對 SQLCipher V4 的,里面有這么一段:

The parameters seem to be the same. I'm wondering if you have to switch the order of key and cipher_page_size in the sqlcipher call. Also the documentation https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_default_page_size seems to indicate that you have to use cipher_default_page_size in the command line call. But it shouldn't make any difference anyway since 4096 is the default value in SQLCipher 4.

說明 SQLCipher 的 cipher_page_size 有默認值,并且在調(diào)用 sqlcipher 加密的時候,會受影響。所以,在可視化頁面連接的時候要指定。

回看代碼

dbname := fmt.Sprintf("db?_pragma_key=x'%s'&_pragma_cipher_page_size=4096", key)

這個庫只支持 SQLCipher v3,v4 的默認值才是 4096,v3的默認值是1024(雖然我不知道這個什么用)

各個可視化工具默認都是 1024,跟代碼里面 4096 對不上,改參數(shù)

改參數(shù)

sqlcipher

sqlite> PRAGMA key = "x'passphrase'";
sqlite> PRAGMA cipher_page_size=4096;
sqlite> SELECT * from test;
1|Hello, World!
sqlite> .exit

db browser

先選 SQLCipher 3, 然后選擇 Custom,再點擊 Page size 的下拉選擇 4096,就可以了

DBeaver

修改 legacy_page_size 為 4096 就可以了

總結(jié)

其實這個懂的人,估計看到這個 page size 不同就知道要去配置了。對于不懂的人,看密碼,又登入不進去就會很煩,就會亂。

后面分析的方法就是從單測入手,用最簡單的方式先跑通一個。比如,密碼先不要設置那么復雜的,就設置 123456,然后測試。通過再往下一步,往自己收到的問題去靠。

以上就是使用Go和Gorm實現(xiàn)讀取SQLCipher加密數(shù)據(jù)庫的詳細內(nèi)容,更多關于Go Gorm讀取SQLCipher的資料請關注腳本之家其它相關文章!

相關文章

  • go語言中的Carbon庫時間處理技巧

    go語言中的Carbon庫時間處理技巧

    這篇文章主要介紹了go語言中的Carbon庫時間處理,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Go語言學習筆記之錯誤和異常詳解

    Go語言學習筆記之錯誤和異常詳解

    Go語言采用返回值的形式來返回錯誤,這一機制既可以讓開發(fā)者真正理解錯誤處理的含義,也可以大大降低程序的復雜度,下面這篇文章主要給大家介紹了關于Go語言學習筆記之錯誤和異常的相關資料,需要的朋友可以參考下
    2022-07-07
  • Go語言中defer使用的陷阱小結(jié)

    Go語言中defer使用的陷阱小結(jié)

    本文主要介紹了Go語言中defer使用的陷阱小結(jié),分別是defer語句不可以在return語句之后,defer語句執(zhí)行的匿名函數(shù),匿名函數(shù)的參數(shù)會被預先處理,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Go的gin參數(shù)校驗中的validator庫詳解

    Go的gin參數(shù)校驗中的validator庫詳解

    這篇文章主要介紹了Go的gin參數(shù)校驗之validator庫,使用 validator 以后,只需要在定義結(jié)構(gòu)體時使用 binding 或 validate tag標識相關校驗規(guī)則,就可以進行參數(shù)校驗了,而不用自己單獨去寫常見的校驗規(guī)則,需要的朋友可以參考下
    2023-08-08
  • 深入了解Golang的指針用法

    深入了解Golang的指針用法

    與C語言一樣,Go語言中同樣有指針,通過指針,我們可以只傳遞變量的內(nèi)存地址,而不是傳遞整個變量,這在一定程度上可以節(jié)省內(nèi)存的占用。本文將通過示例詳細講講Golang的指針用法,需要的可以參考一下
    2022-07-07
  • 關于golang中map使用的幾點注意事項總結(jié)(強烈推薦!)

    關于golang中map使用的幾點注意事項總結(jié)(強烈推薦!)

    map是一種無序的基于key-value的數(shù)據(jù)結(jié)構(gòu),Go語言中的map是引用類型,必須初始化才能使用,下面這篇文章主要給大家介紹了關于golang中map使用的幾點注意事項,需要的朋友可以參考下
    2023-01-01
  • go流程控制代碼詳解

    go流程控制代碼詳解

    這篇文章主要介紹了go流程控制,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-05-05
  • Go語言開發(fā)快速學習CGO編程

    Go語言開發(fā)快速學習CGO編程

    這篇文章主要為大家介紹了Go語言開發(fā)之快速學習CGO編程,看了本文你就會發(fā)現(xiàn)CGO編程其實沒有想象的那么難,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Golang 并發(fā)讀寫鎖的具體實現(xiàn)

    Golang 并發(fā)讀寫鎖的具體實現(xiàn)

    Go語言中的sync.RWMutex提供了讀寫鎖機制,允許多個協(xié)程并發(fā)讀取共享資源,但在寫操作時保持獨占性,本文主要介紹了Golang 并發(fā)讀寫鎖的具體實現(xiàn),感興趣的可以了解一下
    2025-02-02
  • 淺談go語言中別名類型的使用

    淺談go語言中別名類型的使用

    類型別名是 Go 1.9 版本添加的新功能,主要用于解決代碼升級、遷移中存在的類型兼容性問題,本文主要介紹了go語言中別名類型的使用,感興趣的可以了解一下
    2024-01-01

最新評論