V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
CurChen
V2EX  ›  Go 编程语言

go 如何直接打开加密的 sqlite3 db 文件

  •  
  •   CurChen · 2021-12-30 12:02:25 +08:00 · 3895 次点击
    这是一个创建于 1063 天前的主题,其中的信息可能已经有所发展或是发生改变。

    尝试过

    都失败了

    打开 db 代码如下:

    	dbname := `***.db`
    	key := "dd85344"
    	dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s&_pragma_cipher_page_size=4096", key)
    	db, err := gorm.Open(sqlite.Open(dbnameWithDSN), &gorm.Config{})
    

    也尝试过\

    	dbname := `***.db`
    	key := "dd85344"
    	dbnameWithDSN := dbname + fmt.Sprintf("?_pragma_key=%s&_pragma_cipher_page_size=4096", key)
    	db, _ := sql.Open("sqlite3", dbname)
    

    密码肯定是对的,不过我这边的 key 是 7 位的,官方说的是必须为 32 字节十六进制编码
    我觉得问题应该出现在这,但是我不知道该怎么下一步转换了

    第 1 条附言  ·  2021-12-31 09:37:53 +08:00
    继续看了 sql.open 的源码,发现该接口好像仅支持_pragma_key 、_pragma_cipher_page_size 这两个参数
    但是解密数据库其他两个参数是必须的
    目前的解决方案是用 sqlcipher.exe 做一个解密后的 db 文件备份,然后直接打开这个备份文件。
    不过我觉得这样子不优雅,我想直接 open 加密的数据库文件
    emmm 有大佬知道该怎么做吗
    第 2 条附言  ·  2021-12-31 10:01:25 +08:00
    目前解密 db 需要四个参数
    sqlcipher.exe F:\testdata\xxx.db
    sqlite> PRAGMA key = 'dd85344';
    sqlite> PRAGMA cipher_use_hmac = off;
    sqlite> PRAGMA cipher_page_size = 1024;
    sqlite> PRAGMA kdf_iter = 4000;
    sqlite> .table

    但是 sql.open 好像仅支持 PRAGMA key 、PRAGMA cipher_page_size 这两个
    11 条回复    2024-09-11 23:54:53 +08:00
    hemingway
        1
    hemingway  
       2021-12-30 12:05:49 +08:00
    ```
    _pragma_key=x'%s'
    ```
    %s 前面有 x 你的没有,你改下试试
    CurChen
        2
    CurChen  
    OP
       2021-12-30 12:13:31 +08:00
    @hemingway
    db, err := sql.Open("sqlite3", fmt.Sprintf("%s?_pragma_key=x'%s'&_pragma_cipher_page_size=4096", dbname, key))
    db, err := sql.Open("sqlite3", fmt.Sprintf("%s?_pragma_key=x%s&_pragma_cipher_page_size=4096", dbname, key))
    db, err := sql.Open("sqlite3", fmt.Sprintf("%s?_pragma_key=%s&_pragma_cipher_page_size=4096", dbname, key))
    都不行的
    junnplus
        3
    junnplus  
       2021-12-30 14:19:38 +08:00
    你用的 v4 的包么?好像用 v4 没问题
    junnplus
        4
    junnplus  
       2021-12-30 14:24:42 +08:00
    ```
    dbname = fmt.Sprintf("%s?_pragma_key=passphrase&_pragma_cipher_page_size=4096", dbname)
    db, err := sql.Open("sqlite3", dbname)
    if err != nil {
    panic(err)
    }
    ```
    CurChen
        5
    CurChen  
    OP
       2021-12-30 14:47:36 +08:00
    @junnplus 是 v4 的包
    go.mod
    github.com/mutecomm/go-sqlcipher/v4 v4.4.2 // indirect

    我觉得应该是 key 出的问题,不知道该怎么把 7 位字符的 key 转成官方要的 32 字节十六进制编码
    junnplus
        6
    junnplus  
       2021-12-30 14:53:22 +08:00
    @CurChen 不需要转,你看我上面的代码,没问题的
    Mitt
        7
    Mitt  
       2021-12-30 14:56:45 +08:00
    hex.EncodeToString([]byte("dd85344"))
    Mitt
        8
    Mitt  
       2021-12-30 14:58:58 +08:00
    不对我看错了
    CurChen
        9
    CurChen  
    OP
       2021-12-30 15:24:51 +08:00
    @junnplus
    db, err := sql.Open("sqlite3", `xxx.db?_pragma_key=dd85344&_pragma_cipher_page_size=4096`)
    if err != nil {
    t.Fatal(err)
    }
    rows, err := db.Query("SELECT id,value FROM userinfo")
    if err != nil {
    t.Fatal(err)
    }
    最后的 err 会返回:file is not a database
    CurChen
        10
    CurChen  
    OP
       2021-12-30 16:35:38 +08:00
    我使用 sqlcipher.exe 执行
    ```base
    sqlcipher.exe F:\testdata\xxx.db
    sqlite> PRAGMA key = 'dd85344';
    sqlite> PRAGMA cipher_use_hmac = off;
    sqlite> PRAGMA cipher_page_size = 1024;
    sqlite> PRAGMA kdf_iter = 4000;
    sqlite> .table
    ```
    成功了

    这是我的 golang 代码
    ```golang
    import (
    "database/sql"
    "fmt"
    "testing"

    _ "github.com/mutecomm/go-sqlcipher/v4"
    )

    func TestDecrypt(t *testing.T) {
    dbname := fmt.Sprintf("%s?_pragma_key=%s&_pragma_cipher_use_hmac=off&_pragma_cipher_page_size=1024&_pragma_kdf_iter=4000", `F:\testdata\xxx.db`, "dd85344")
    db, err := sql.Open("sqlite3", dbname)
    if err != nil {
    panic(err)
    }
    _, err = db.Query("SELECT id,value FROM userinfo")
    if err != nil {
    panic(err)
    }
    }
    ```
    最后的 error 会报错 : "file is not a database"
    Felldeadbird
        11
    Felldeadbird  
       77 天前
    @CurChen 楼主最后找到答案了吗? 我也被困扰了好久。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1089 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:43 · PVG 06:43 · LAX 14:43 · JFK 17:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.