分类 Go 下的文章

“Go是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。 罗伯特·格瑞史莫、罗勃·派克及肯·汤普逊于2007年9月开始设计Go,稍后伊恩·兰斯·泰勒、拉斯·考克斯加入项目。Go是基于Inferno操作系统所开发的。”

gocv介绍
gocv是OpenCV4在Go中的绑定,使用它可以在Go里做图像处理。
Github: https:/​/github.com/hybridgroup/gocv
opencv介绍
OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行。

Ubuntu/Linux安装步骤

go get -u -d gocv.io/x/gocv
cd ~/go/pkg/mod/gocv.io/x/gocv@v0.27.0

编译动态库

sudo make install

编译静态库

sudo make install BUILD_SHARED_LIBS=OFF

验证安装

go run ./cmd/version/main.go

运行结果:

gocv version: 0.27.0
opencv lib version: 4.5.2

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被称为Base64。
Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。

在MIME格式的电子邮件中,Base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定Base64。使用的字符包括大小写拉丁字母各26个、数字10个、加号+和斜杠/,共64个字符,等号=用来作为后缀用途。

编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。
base64 go 语言示例

package main

import (
    b64 "encoding/base64"
    "fmt"
)

func main() {

    data := "abc123!?$*&()'-=@~"

    sEnc := b64.StdEncoding.EncodeToString([]byte(data))
    fmt.Println(sEnc)

    sDec, _ := b64.StdEncoding.DecodeString(sEnc)
    fmt.Println(string(sDec))
    fmt.Println()

    uEnc := b64.URLEncoding.EncodeToString([]byte(data))
    fmt.Println(uEnc)
    uDec, _ := b64.URLEncoding.DecodeString(uEnc)
    fmt.Println(string(uDec))
}

sha256withrsa 是先将数据使用sha256 计算hash值,然后再使用rsa 对hash sign的算法。

go sha256withrsa代码

func sha256withrsa(signContent string, strprikey string) string {
    hash := crypto.SHA256
    shaNew := hash.New()
    shaNew.Write([]byte(signContent))
    hashed := shaNew.Sum(nil)
    priKey, err := ParsePrivateKey(strprikey)
    if err != nil {
        panic(err)
    }

    signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, hashed)
    if err != nil {
        panic(err)
    }
    return b64.StdEncoding.EncodeToString(signature)
}
func ParsePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode([]byte(privateKey))
    if block == nil {
        return nil, errors.New("私钥信息错误!")
    }
    priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return priKey, nil
}

生成rsa私钥

openssl genrsa 

Generating RSA private key, 2048 bit long modulus (2 primes)
...........................................................+++++
...............................................................+++++
e is 65537 (0x010001)
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAw3PgS6PELTZtchDBmFSzK329CaZLV/mOr1IP595Q3pVsYkr/
uNHVqvdtyEiJ42uj+Q9d2u4cOLU8G9DWsWBdHgbWZORKJjMrgpIFb4CVfWs9eqil
XO2vDqDiUjL1idPHLXwm7Z8SDEOUaFLTFKCJJxS3RkArRtcRgrCekA10XNHnnOm5
6+96SD/X2edUH++fiWkrmNvi+P2tLoTphCRePmucyOLKJH/V+nBhV83zq+4KyxBs
xLUwOeEDaf6JbOGUb81WYDUCmkBjyffdLDaD1gJRxtj2zkSx0GL4ROnWGMXbrIj4
ZxiJSktGi0jatzI7HhnCaCB+ya+y8MP/5ExRDwIDAQABAoIBAQCu879XFa1ZpzmK
e9M+7ro+eNvIknEou3rsFjGkpIyQ4QHWbjm/Dx0KX1aGi9/ZkRWCsC2b9b2PSTMX
1vUGazKO2SH5x5tT3EPbKafx6hBl5qNucx0qNJuZJYvQdkrxZ38HiPUziErYbXmf
dFv7P8PlFpcDLBdQ3tyOtlgIq/J3zd/MabjSXvOI7sr89TJjpfXexGYI/gZvhGw1
CeXHu4b+iVbGKBpD0SD3m8T7LkJ9ELifPCQS6wmJpmZOqpFIGzcZGSuYV29H5nFr
+sDfAqfbkulKzqJkS1HNQvRpwyua7SdIOb+HMQ+bRo56hnDXJG5xB14sJlaBjDiZ
Hl9Y/9IpAoGBAOTWQSPSlPDDKm54AS5u1z2yXClb3c8TjX9N1C7uvHMPvjI2HLRH
Xs0AAZZUGLYfkFBlJRrb39z5drRJ0u70pFkPLOBf7Z0x0rMOCmi8Rd8b19myNhZH
4UmssiCqOUKFPvUaPDEVsFPlYkNJ/99gMSz6PT1luxqS+ySH8IHz7f07AoGBANqn
KXS12mirOiW61a0js/vcbQzut3+T4/R1sPKk3azz5OOS2lUExOIi4O7P1Ugcpi3Z
kpQZ3IB4yL6IF88WNeUztBvNHKc9iosKicrjKHMgQrPS4ZTJBsYPsSqjORdOCGK7
VWg4TsJWl20XsWm0dvujs/TGidg95w8lziuZXU49AoGARed9dqf5f6Le72gRVFHf
xqUZqji6BWv/qYfo7X1Ya/2/KC+HjTrQJud9lKKT+e6icyyyrQXF2QcLz/9NRFnP
arVMDC7Bs2do6fG8FEqPPZyPz5y1ERFcLNlogLn/S+bQWKdvA7+QYdCMt+l/FImZ
/BdlZcAR7AhCV+J/AfO2G8kCgYBl/PzYRI7Yra2Utb4/YVztiNaQ5rRO3MPCXjco
JwCDUMwd3nzalTvkoxI6MlUwqrRUxJybWijBABXa0Y4ReTGwdFp5cUYBODJsQoEd
UrGmaZDTYfT4un/fWKhx0+qoVSySKQFgeIs8GLnPF/MX9CZfn+8rqIPZip5BMYgm
TAX6nQKBgE6e3iYTj7CqXSOpzkFyQnsvY/P7vZxk/feR/JB8dHvhAJ3JTuiVDaM6
PVP5oq7+HfIZo1rkjID6W4WuqLPm/I+h4qx+gDw+Jiepolt7jML3F7tle32ifDa8
zTmQ57Qa/fT5Wx5sXberOok233bRHSPoct09q2TgZ34vA90BHzUT
-----END RSA PRIVATE KEY-----

调用示例,这里面有一个go语言输入多行字符的技巧,使用 ` 来包含即可。

prikey := `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAw3PgS6PELTZtchDBmFSzK329CaZLV/mOr1IP595Q3pVsYkr/
.........此处有省略..............................................
zTmQ57Qa/fT5Wx5sXberOok233bRHSPoct09q2TgZ34vA90BHzUT
-----END RSA PRIVATE KEY-----
`  
str := sha256withrsa("const.net.cn", prikey)
fmt.Printf("sha256withrsa = %s", str)

运行结果:

Ye1ErpEaY/fdH13peaczvCzeTkGa4xl6Ms3AH99zl3Q3x1cGBtFt7+VeWSvLtyRuIt2b+e71q6V4QJM8VYGPDtVWtHARQlinznYvib0c4NSaVSvz6d6P99vDL1IWe1v9kJMtGNaBw0B5lwY2gxl4ta14Xka6T/XK5wPiSFiINIMizhpAbs7olu/csyLaYUMe1tTdVCIF8AQzkGSUZWcz2QhxiVHdh4/uC2PxV7Zhos7XVKhJPHw3e99ktpfgzqz0X7c8et2+4xrLYFM01MNUAnbRjNkGdqXrxkIprbSZwII8B+ttQgUUebUj9N/GFVjWH1pmqwLaKnpH1x2G40aDWw==

openssl 验证 sha256withrsa

将刚才生成的私钥保存为pri.pem,然后执行以下命令

echo -ne "const.net.cn" > test.txt
openssl dgst -sha256 -sign pri.pem test.txt |openssl base64

Ye1ErpEaY/fdH13peaczvCzeTkGa4xl6Ms3AH99zl3Q3x1cGBtFt7+VeWSvLtyRu
It2b+e71q6V4QJM8VYGPDtVWtHARQlinznYvib0c4NSaVSvz6d6P99vDL1IWe1v9
kJMtGNaBw0B5lwY2gxl4ta14Xka6T/XK5wPiSFiINIMizhpAbs7olu/csyLaYUMe
1tTdVCIF8AQzkGSUZWcz2QhxiVHdh4/uC2PxV7Zhos7XVKhJPHw3e99ktpfgzqz0
X7c8et2+4xrLYFM01MNUAnbRjNkGdqXrxkIprbSZwII8B+ttQgUUebUj9N/GFVjW
H1pmqwLaKnpH1x2G40aDWw==

echo -ne "const.net.cn" | openssl dgst -sha256 -sign pri.pem |openssl base64

Ye1ErpEaY/fdH13peaczvCzeTkGa4xl6Ms3AH99zl3Q3x1cGBtFt7+VeWSvLtyRu
It2b+e71q6V4QJM8VYGPDtVWtHARQlinznYvib0c4NSaVSvz6d6P99vDL1IWe1v9
kJMtGNaBw0B5lwY2gxl4ta14Xka6T/XK5wPiSFiINIMizhpAbs7olu/csyLaYUMe
1tTdVCIF8AQzkGSUZWcz2QhxiVHdh4/uC2PxV7Zhos7XVKhJPHw3e99ktpfgzqz0
X7c8et2+4xrLYFM01MNUAnbRjNkGdqXrxkIprbSZwII8B+ttQgUUebUj9N/GFVjW
H1pmqwLaKnpH1x2G40aDWw==

还有个php来验证的代码:

cat sha256withrsa.php 
<?php
$sign = "const.net.cn";
$binary_signature = "";
$prikey = "-----BEGIN RSA PRIVATE KEY-----
........................此处有省略..........
-----END RSA PRIVATE KEY-----";
$algo = "SHA256";
openssl_sign($sign, $binary_signature, $prikey, $algo);
$sign = base64_encode($binary_signature);
echo $sign;
?>
php7.4 sha256withrsa.php 

Ye1ErpEaY/fdH13peaczvCzeTkGa4xl6Ms3AH99zl3Q3x1cGBtFt7+VeWSvLtyRuIt2b+e71q6V4QJM8VYGPDtVWtHARQlinznYvib0c4NSaVSvz6d6P99vDL1IWe1v9kJMtGNaBw0B5lwY2gxl4ta14Xka6T/XK5wPiSFiINIMizhpAbs7olu/csyLaYUMe1tTdVCIF8AQzkGSUZWcz2QhxiVHdh4/uC2PxV7Zhos7XVKhJPHw3e99ktpfgzqz0X7c8et2+4xrLYFM01MNUAnbRjNkGdqXrxkIprbSZwII8B+ttQgUUebUj9N/GFVjWH1pmqwLaKnpH1x2G40aDWw==

urlencode
golang下可以使用net/url模块实现urlencode和urldecode操作。
urlencode具体实现的函数为url.QueryEscape

urldecode具体实现的函数为url.QueryUnescape

另外 url.ParseRequestURI

QueryUnescape会处理+以及%20变成空格,ParseRequestURI只把%20变成空格

根据最新的RFC3986

1 URI中的字段只能空格编码成%20

golang使用ParseRequestURI来解析,符合标准

2 query string作为application/x-www-form-urlencoded的方式,可以编码成+,也可以编码成%20

URL中不管是URI还是query string,编码成%20

示例:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    s := "this will be esc@ped!"
    fmt.Println("http://example.com/say?message="+url.QueryEscape(s))
}

输出结果
http://example.com/say?message=this+will+be+esc%40ped%21

表单编码

params := url.Values{}
params.Add("message", "this will be esc@ped!")
params.Add("author", "golang c@fe >.<")
fmt.Println("http://example.com/say?"+params.Encode())