分类 Demo 下的文章

“各种示例”

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。
aes-192密钥的长度为24字节,aes-256密钥的长度为32字节,aes-128密码的长度为16字节。aes-ccm需要key,nonce,adata,另外aes-gcm不需要填充。
GCM ( Galois/Counter Mode) 指的是该对称加密采用Counter模式,并带有GMAC消息认证码。
aes-gcm 在线加密工具:https://const.net.cn/tool/aes/aes-gcm/
代码:

package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/md5"
    "fmt"
)

func main() {
    fmt.Println("go crypto aes-128-gcm demo/example.")
    message := []byte("https://const.net.cn/")
    //指定密钥h
    key := []byte("1234567812345678")
    fmt.Printf("key.size = %d\n", len(key))
    //加密
    cipherText := AES_GCM_Encrypt(message, key)
    fmt.Printf("加密后:%x len = %d\n", cipherText, len(cipherText))
    fmt.Printf("MD5后为:%x\n", md5.Sum(cipherText))
    //解密
    plainText := AES_GCM_Decrypt(cipherText, key)
    fmt.Println("解密后为:", string(plainText))
}

//AES加密(GCM模式)
func AES_GCM_Encrypt(plainText []byte, key []byte) []byte {
    //指定加密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始向量vi,长度为12
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //blockMode, _ := cipher.NewGCM(block)
    //加密连续
    cipherText := make([]byte, len(plainText))
    cipherText = blockMode.Seal(cipherText[:0], iv, plainText, additionalData)
    //返回密文
    return cipherText
}

//AES解密(GCM模式)
func AES_GCM_Decrypt(cipherText []byte, key []byte) []byte {
    //指定解密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始化向量IV,和加密的一致
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //解密
    plainText := make([]byte, len(cipherText))
    plainText, _ = blockMode.Open(plainText[:0], iv, cipherText, additionalData)

    return plainText
}

输出 :

go run .
go crypto aes-128-gcm demo/example.
key.size = 16
加密后:e9d73cf873cd04b8ffe2936cd68038db06b419ac273a44ad58737993ed30c4a3656c917077 len = 37
MD5后为:2067cb77198e25a0dbcc488d7663169b
解密后为: https://const.net.cn/

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。
aes-192密钥的长度为24字节,aes-256密钥的长度为32字节,aes-128密码的长度为16字节。aes-ccm需要key,nonce,adata,另外aes-gcm不需要填充。
GCM ( Galois/Counter Mode) 指的是该对称加密采用Counter模式,并带有GMAC消息认证码。
aes-gcm 在线加密工具:https://const.net.cn/tool/aes/aes-gcm/
代码:

package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/md5"
    "fmt"
)

func main() {
    fmt.Println("go crypto aes-192-gcm demo/example.")
    message := []byte("https://const.net.cn/ aes-192-gcm test vectors.")
    //指定密钥h
    key := []byte("123456781234567812345678")
    fmt.Printf("key.size = %d\n", len(key))
    //加密
    cipherText := AES_GCM_Encrypt(message, key)
    fmt.Printf("加密后:%x len = %d\n", cipherText, len(cipherText))
    fmt.Printf("MD5后为:%x\n", md5.Sum(cipherText))
    //解密
    plainText := AES_GCM_Decrypt(cipherText, key)
    fmt.Println("解密后为:", string(plainText))
}

//AES加密(GCM模式)
func AES_GCM_Encrypt(plainText []byte, key []byte) []byte {
    //指定加密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始向量vi,长度为12
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //blockMode, _ := cipher.NewGCM(block)
    //加密连续
    cipherText := make([]byte, len(plainText))
    cipherText = blockMode.Seal(cipherText[:0], iv, plainText, additionalData)
    //返回密文
    return cipherText
}

//AES解密(GCM模式)
func AES_GCM_Decrypt(cipherText []byte, key []byte) []byte {
    //指定解密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始化向量IV,和加密的一致
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //解密
    plainText := make([]byte, len(cipherText))
    plainText, _ = blockMode.Open(plainText[:0], iv, cipherText, additionalData)

    return plainText
}

输出 :

go run .
go crypto aes-192-gcm demo/example.
key.size = 24
加密后:085d12a881561fd6d0f4977222ada32a49d48b24e7a862a26d6c459344d9f6e57083476dd3d0107c6d13a0229e3809fdf1a1052ae652ac624867d729b9a49f len = 63
MD5后为:2db9ab0073956f1fb4ac61e4e92241fe
解密后为: https://const.net.cn/ aes-192-gcm test vectors.

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。
aes-192密钥的长度为24字节,aes-256密钥的长度为32字节,aes-128密码的长度为16字节。aes-ccm需要key,nonce,adata,另外aes-gcm不需要填充。
GCM ( Galois/Counter Mode) 指的是该对称加密采用Counter模式,并带有GMAC消息认证码。
aes-gcm 在线加密工具:https://const.net.cn/tool/aes/aes-gcm/
代码:

package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/md5"
    "fmt"
)

func main() {
    fmt.Println("go crypto aes-256-gcm demo/example.")
    message := []byte("https://const.net.cn/ aes-256-gcm test vectors.")
    //指定密钥h
    key := []byte("12345678123456781234567812345678")
    fmt.Printf("key.size = %d\n", len(key))
    //加密
    cipherText := AES_GCM_Encrypt(message, key)
    fmt.Printf("加密后:%x len = %d\n", cipherText, len(cipherText))
    fmt.Printf("MD5后为:%x\n", md5.Sum(cipherText))
    //解密
    plainText := AES_GCM_Decrypt(cipherText, key)
    fmt.Println("解密后为:", string(plainText))
}

//AES加密(GCM模式)
func AES_GCM_Encrypt(plainText []byte, key []byte) []byte {
    //指定加密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始向量vi,长度为12
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //blockMode, _ := cipher.NewGCM(block)
    //加密连续
    cipherText := make([]byte, len(plainText))
    cipherText = blockMode.Seal(cipherText[:0], iv, plainText, additionalData)
    //返回密文
    return cipherText
}

//AES解密(GCM模式)
func AES_GCM_Decrypt(cipherText []byte, key []byte) []byte {
    //指定解密算法,返回一个AES算法的Block接口对象
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    //指定初始化向量IV,和加密的一致
    iv := []byte("123456781234")
    additionalData := []byte("12345678")
    //指定分组模式,返回一个BlockMode接口对象
    blockMode, _ := cipher.NewGCMWithNonceSize(block, len(iv))
    //解密
    plainText := make([]byte, len(cipherText))
    plainText, _ = blockMode.Open(plainText[:0], iv, cipherText, additionalData)

    return plainText
}

输出:

go run .
go crypto aes-256-gcm demo/example.
key.size = 32
加密后:e256d43a63f05a71c64a3c20ecd1cf579acbb1f7463a15b5c0c72ea4c78139d6b67bb344c1595d6ba24e9e6398193b887e85677cbdde78218b5bccd96532d5 len = 63
MD5后为:8874a42e73b2df1f8831e4710c7f8744
解密后为: https://const.net.cn/ aes-256-gcm test vectors.

经常使用UDP发送数据,但一般都是小包,没有太关注过发送大包的问题。突然要发个大包,c++ udp send big packet。
就tcpdump wireshark抓包看了一下。
结果在tcpdump中,出现了这个东西。
UDP, bad length 5455 > 1472
看来UDP包长度超过MTU了。应该是分片了,但分片就分片,只要网络可靠,应该都没什么问题。

另外就是怕UDP的接收或者发送缓冲区不够了。

udp setsockopt sendbuf example

还有多网卡的问题。直接指定网卡,这个要用到struct ifreq.这是linux下的用法。
windows好像没有这个SO_BINDTODEVICE选项,不过可以使用静态路由的方式。可以参考这个链接:
多网卡指定网卡进行UDP通信(添加静态路由解决双网卡问题 )全记录
最后代码如下:

注意 struct ifreq 头文件如下: struct ifreq header file

#include <sys/ioctl.h>
#include <net/if.h>

int cudp::udp_send(string ip, int port, string data)
{
    printf("udp_send ip=%s,port=%d\n",ip.c_str(),port);
    int m_nsockfd;
    if ((m_nsockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("udp_send error.\n");
        return -1;
    }
    struct ifreq ifr;
    memset(&ifr, 0x00, sizeof(ifr));
    strncpy(ifr.ifr_name, "eth0", 4);
    setsockopt(m_nsockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));

    int addrlen = sizeof(sockaddr_in);
    struct sockaddr_in addr;
    bzero(&addr, sizeof(struct sockaddr_in));    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    int sendbuff;
    socklen_t optlen;
    int res = 0;

    // Get buffer size
    optlen = sizeof(sendbuff);
    res = getsockopt(m_nsockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);

    if(res == -1)
        printf("Error getsockopt one");
    else
        printf("send buffer size = %d\n", sendbuff);

    sendbuff = 50*1024;

    printf("sets the send buffer to %d\n", sendbuff);
    res = setsockopt(m_nsockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));

    if(res == -1)
        printf("Error setsockopt");
        
    int ret = sendto(m_nsockfd, data.data(), data.length(), 0, (struct sockaddr *)&addr, addrlen);
    printf("sendto ret = %d\n", ret);
    return ret;
}

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==