使用Golang将MSSQL数据导出到加密文件

使用Golang将MSSQL数据导出到加密文件 大家好,

我需要将大量数据从 MSSQL 查询导出到加密的平面文件中。

要求是“静态数据”必须被加密,并且不能先将其以未加密的形式保存到磁盘上。如果可以先将其未加密保存到磁盘,我完全可以在 CSV 文件生成后运行 PGP 对其进行加密。

这意味着我需要从数据库获取数据后,在内存中对其进行加密,很可能通过使用流的方式来实现。

为了避免在处理大量数据行时耗尽内存,更好的做法是分块地将数据(以加密格式)写入磁盘。也就是说,读取一小部分,写入一小部分(加密后)。

这可行吗?能否提供一些伪代码帮助?

2 回复

基本上,你可以从数据库中读取每一行(或一组行),并使用AES或PK(即RSA等公钥)单独加密。

相关资源:

The Polyglot Developer

使用Crypto包在Golang应用程序中加密和解密数据

学习如何在Golang应用程序中使用可用的加密包通过AES加密和解密数据。

https://gist.github.com/miguelmota/3ea9286bd1d3c2a985b67cac4ba2130a

rsa_util.go
package ciphers

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha512"
	"crypto/x509"
	"encoding/pem"
  "log"
)

此文件已被截断。显示原文

更多关于使用Golang将MSSQL数据导出到加密文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


可以使用Go的database/sqlcrypto/cipher包流式处理数据并加密写入文件。以下是一个示例实现:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "database/sql"
    "encoding/csv"
    "io"
    "os"
    
    _ "github.com/denisenkom/go-mssqldb"
)

func main() {
    // 1. 数据库连接
    connStr := "server=localhost;user id=sa;password=your_password;database=your_db"
    db, err := sql.Open("sqlserver", connStr)
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 2. 创建加密文件
    key := make([]byte, 32) // AES-256密钥
    if _, err := rand.Read(key); err != nil {
        panic(err)
    }
    
    outputFile, err := os.Create("encrypted_data.bin")
    if err != nil {
        panic(err)
    }
    defer outputFile.Close()

    // 3. 初始化加密流
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    
    iv := make([]byte, aes.BlockSize)
    if _, err := rand.Read(iv); err != nil {
        panic(err)
    }
    
    // 写入IV到文件头部
    if _, err := outputFile.Write(iv); err != nil {
        panic(err)
    }
    
    stream := cipher.NewCFBEncrypter(block, iv)
    writer := &cipher.StreamWriter{S: stream, W: outputFile}

    // 4. 创建CSV写入器包装加密流
    csvWriter := csv.NewWriter(writer)
    defer csvWriter.Flush()

    // 5. 流式查询和写入
    rows, err := db.Query("SELECT col1, col2, col3 FROM large_table")
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    cols, err := rows.Columns()
    if err != nil {
        panic(err)
    }

    // 缓冲区大小(每次处理1000行)
    bufferSize := 1000
    buffer := make([][]string, 0, bufferSize)
    
    for rows.Next() {
        row := make([]string, len(cols))
        rowPtrs := make([]interface{}, len(cols))
        for i := range row {
            rowPtrs[i] = &row[i]
        }
        
        if err := rows.Scan(rowPtrs...); err != nil {
            panic(err)
        }
        
        buffer = append(buffer, row)
        
        // 缓冲区满时写入加密文件
        if len(buffer) >= bufferSize {
            if err := csvWriter.WriteAll(buffer); err != nil {
                panic(err)
            }
            buffer = buffer[:0] // 清空缓冲区
        }
    }
    
    // 写入剩余数据
    if len(buffer) > 0 {
        if err := csvWriter.WriteAll(buffer); err != nil {
            panic(err)
        }
    }
    
    if err := rows.Err(); err != nil {
        panic(err)
    }
}

如果需要使用PGP加密,可以使用golang.org/x/crypto/openpgp包:

package main

import (
    "database/sql"
    "io"
    "os"
    
    "golang.org/x/crypto/openpgp"
    "golang.org/x/crypto/openpgp/armor"
    
    _ "github.com/denisenkom/go-mssqldb"
)

func pgpEncryptStream() {
    // ... 数据库连接代码同上 ...
    
    // 创建加密文件
    encryptedFile, err := os.Create("encrypted_data.pgp")
    if err != nil {
        panic(err)
    }
    defer encryptedFile.Close()

    // 读取PGP公钥
    pubKeyFile, err := os.Open("public.key")
    if err != nil {
        panic(err)
    }
    defer pubKeyFile.Close()
    
    entityList, err := openpgp.ReadArmoredKeyRing(pubKeyFile)
    if err != nil {
        panic(err)
    }

    // 创建加密流
    armorWriter, err := armor.Encode(encryptedFile, "PGP MESSAGE", nil)
    if err != nil {
        panic(err)
    }
    defer armorWriter.Close()
    
    plainWriter, err := openpgp.Encrypt(armorWriter, entityList, nil, nil, nil)
    if err != nil {
        panic(err)
    }
    defer plainWriter.Close()

    // 流式处理数据
    rows, err := db.Query("SELECT col1, col2, col3 FROM large_table")
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    // 直接写入加密流(这里简化为文本格式)
    for rows.Next() {
        var col1, col2, col3 string
        if err := rows.Scan(&col1, &col2, &col3); err != nil {
            panic(err)
        }
        
        line := col1 + "," + col2 + "," + col3 + "\n"
        if _, err := plainWriter.Write([]byte(line)); err != nil {
            panic(err)
        }
    }
}

这个方案通过流式处理避免了内存溢出,数据在内存中始终以加密形式存在,不会在磁盘上留下未加密的临时文件。

回到顶部