(二)wireguard-tools源码解读之genkey_main

文章详细介绍了如何使用genkey_main模块生成用户私钥和预共享密钥,涉及Base64编码和Curve25519算法。通过调用getrandom_bytes获取随机数,再经curve25519_clamp_secret处理生成私钥,最后通过key_to_base64将密钥转换为Base64字符串。此外,还阐述了Base64编码的基本原理和Curve25519的用途。
摘要由CSDN通过智能技术生成


前言

genkey_main模块,主要用于生成用户私钥和预共享密钥。
启动wg genkey 和 wk genpsk ,都是调用该模块。


源码详解

int genkey_main(int argc, const char *argv[])
{
	/*
	key(是32个单字节编码的字符数组
	*/
	uint8_t key[WG_KEY_LEN];
	/*
	把原始key转换成base64编码的字符串,所以需要在数组最后面加上'/0',长度成了44+1=45.
	*/
	char base64[((((WG_KEY_LEN) + 2) / 3) * 4 + 1)];
	struct stat stat;

	if (argc != 1) {
		fprintf(stderr, "Usage: %s %s\n", PROG_NAME, argv[0]);
		return 1;
	}
    /*
	标准C函数
	struct stat,是一个保存文件状态信息的结构体.
	文件操作权限的检查。可以Linux 文件操作的C函数库。
	*/
	if (!fstat(STDOUT_FILENO, &stat) && S_ISREG(stat.st_mode) && stat.st_mode & S_IRWXO)
		fputs("Warning: writing to world accessible file.\nConsider setting the umask to 077 and trying again.\n", stderr);

    /*
    如下是调用系统函数__NR_getrandom,获取32字节随机数key
	*/
	if (!get_random_bytes(key, WG_KEY_LEN)) {
		perror("getrandom");
		return 1;
	}
	/*
	如果是生成私钥的指令,需要再将随机数key,转换成curve25519算法处理的key
	如果是生成预共享密钥额指令,就不执行curve25519
	*/
	if (!strcmp(argv[0], "genkey"))
		curve25519_clamp_secret(key);
	/*
	将key编码成base64,函数调用见以下的代码
	*/
	key_to_base64(base64, key);
	puts(base64);
	return 0;
}

调用函数

void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN])
{
	unsigned int i;

	for (i = 0; i < WG_KEY_LEN / 3; ++i)
		encode_base64(&base64[i * 4], &key[i * 3]);
	encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
	/*
	根据base64的编码规则,32位的原始数据,不是3的整数倍,需要填补一个字节位,这个位置编码为“=”;
	也就是base64数字的倒数第二位置,最后补上字符串结尾字符'\0'.
	*/
	base64[WG_KEY_LEN_BASE64 - 2] = '=';
	base64[WG_KEY_LEN_BASE64 - 1] = '\0';
}

备注(1)Base64

1.算法介绍

Base64是一种转换算法,常用于网络传输编码用。要求把3个8位字节(38=24)转化为4个6位的字节(46=24)。
先将三个byte(1byte=8bit)的数据转换为ASCII码二进制值,按序放入一个24bit的缓冲区中。

每次取出6个bit,按照其索引值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。
在这里插入图片描述

2.举例说明

举个例子:

在这里插入图片描述
但是转换到最后你发现不够三个字节了怎么办呢?愿望终于实现了,我们可以用两 个Base64来表示一个字符或用三个Base64表示两个字符,像下图的A对应的第二个Base64的二进制位只有两个,把后边的四个补0就是了。所以 A对应的Base64字符就是QQ。原则是Base64字符的最小单位是四个字符一组,那这才两个字符,后边补两个"=“吧。其实不用”=“也不耽误解码,之所以用”=",可能是考虑到多段编码后的Base64字符串拼起来也不会引起混淆。由此可见 Base64字符串只可能最后出现一个或两个"=",中间是不可能出现"="的。下图中字符"BC"的编码过程也是一样的。

在这里插入图片描述
在这里插入图片描述

备注(2)Curve 25519

1. 算法简介

Curve25519 是Diffie-Hellman函数,由Daniel J. Bernstein教授设计。

(1) 给定一个用户的32字节私钥(通常通过随机数,再进行变换的方式获得),curve25519计算该私钥对应的公钥(32字节)。
(2) 给定该用户的32字节私钥和其他用户的32字节公钥,curve25519计算出一个32字节的共享密钥供这两个用户使用。然后可以使用这个密钥对两个用户进行身份验证和信息加密。

2.算法使用

更多关于Curve25519的介绍和用法,可参考https://cr.yp.to/ecdh.html
这个地方都是比较老的内容,但是易于大家理解。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
转python写法:#!/bin/sh time_stamp=`date +%s` function CheckStop() { if [ $? -ne 0 ]; then echo "execute fail, error on line_no:"$1" exit!!!" exit fi } function GenEcdsaKey() { ec_param_file_path="/tmp/ec_param.pem."$time_stamp openssl ecparam -out $ec_param_file_path -name prime256v1 -genkey CheckStop $LINENO openssl genpkey -paramfile $ec_param_file_path -out $1 CheckStop $LINENO openssl pkey -in $1 -inform PEM -out $2 -outform PEM -pubout CheckStop $LINENO rm $ec_param_file_path echo "gen_ecdsa_key succ prikey_path:"$1" pubkey_path:"$2 } function GenEcdsaSign() { ec_sign_info_file="/tmp/ec_sign_info_file."$time_stamp ec_sign_info_sha256="/tmp/ec_sign_info_sha256."$time_stamp ec_binary_sign_file="/tmp/ec_binary_sign_file."$time_stamp echo -n "$1"_"$2" > $ec_sign_info_file openssl dgst -sha256 -binary -out $ec_sign_info_sha256 $ec_sign_info_file CheckStop $LINENO openssl pkeyutl -sign -in $ec_sign_info_sha256 -out $ec_binary_sign_file -inkey $3 -keyform PEM CheckStop $LINENO openssl base64 -e -in $ec_binary_sign_file -out $4 CheckStop $LINENO rm $ec_sign_info_file $ec_sign_info_sha256 $ec_binary_sign_file echo "gen_ecdsa_sign succ sign_file_path:"$4 } function VerifyEcdsaSign() { ec_sign_info_file="/tmp/ec_sign_info_file."$time_stamp ec_sign_info_sha256="/tmp/ec_sign_info_sha256."$time_stamp ec_binary_sign_file="/tmp/ec_binary_sign_file."$time_stamp echo -n "$1"_"$2" > $ec_sign_info_file openssl dgst -sha256 -binary -out $ec_sign_info_sha256 $ec_sign_info_file CheckStop $LINENO openssl base64 -d -in $4 -out $ec_binary_sign_file CheckStop $LINENO openssl pkeyutl -verify -in $ec_sign_info_sha256 -sigfile $ec_binary_sign_file -pubin -inkey $3 -keyform PEM rm $ec_sign_info_file $ec_sign_info_sha256 $ec_binary_sign_file } function Usage() { echo "Usage:" echo "mmiot_ecdsa_sign.sh gen_ecdsa_key <private_key_file_path> <public_key_file_path>" echo "mmiot_ecdsa_sign.sh gen_ecdsa_sign <product_id> <sn> <private_
05-31
以下是转换后的 Python 代码: ```python #!/usr/bin/env python import os import subprocess import base64 time_stamp = str(int(time.time())) def check_stop(line_no, ret): if ret != 0: print("execute fail, error on line_no: ", line_no, " exit!!!") exit() def gen_ecdsa_key(private_key_file_path, public_key_file_path): ec_param_file_path = "/tmp/ec_param.pem." + time_stamp ret = subprocess.call(["openssl", "ecparam", "-out", ec_param_file_path, "-name", "prime256v1", "-genkey"]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "genpkey", "-paramfile", ec_param_file_path, "-out", private_key_file_path]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "pkey", "-in", private_key_file_path, "-inform", "PEM", "-out", public_key_file_path, "-outform", "PEM", "-pubout"]) check_stop(sys._getframe().f_lineno, ret) os.remove(ec_param_file_path) print("gen_ecdsa_key succ prikey_path:", private_key_file_path, " pubkey_path:", public_key_file_path) def gen_ecdsa_sign(product_id, sn, private_key_file_path, sign_file_path): ec_sign_info_file = "/tmp/ec_sign_info_file." + time_stamp ec_sign_info_sha256 = "/tmp/ec_sign_info_sha256." + time_stamp ec_binary_sign_file = "/tmp/ec_binary_sign_file." + time_stamp with open(ec_sign_info_file, 'w') as f: f.write(product_id + "_" + sn) ret = subprocess.call(["openssl", "dgst", "-sha256", "-binary", "-out", ec_sign_info_sha256, ec_sign_info_file]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "pkeyutl", "-sign", "-in", ec_sign_info_sha256, "-out", ec_binary_sign_file, "-inkey", private_key_file_path, "-keyform", "PEM"]) check_stop(sys._getframe().f_lineno, ret) with open(ec_binary_sign_file, 'rb') as f: sign_binary = f.read() sign_base64 = base64.b64encode(sign_binary).decode() with open(sign_file_path, 'w') as f: f.write(sign_base64) os.remove(ec_sign_info_file) os.remove(ec_sign_info_sha256) os.remove(ec_binary_sign_file) print("gen_ecdsa_sign succ sign_file_path:", sign_file_path) def verify_ecdsa_sign(product_id, sn, public_key_file_path, sign_file_path): ec_sign_info_file = "/tmp/ec_sign_info_file." + time_stamp ec_sign_info_sha256 = "/tmp/ec_sign_info_sha256." + time_stamp ec_binary_sign_file = "/tmp/ec_binary_sign_file." + time_stamp with open(ec_sign_info_file, 'w') as f: f.write(product_id + "_" + sn) ret = subprocess.call(["openssl", "dgst", "-sha256", "-binary", "-out", ec_sign_info_sha256, ec_sign_info_file]) check_stop(sys._getframe().f_lineno, ret) with open(sign_file_path, 'r') as f: sign_base64 = f.read() sign_binary = base64.b64decode(sign_base64) with open(ec_binary_sign_file, 'wb') as f: f.write(sign_binary) ret = subprocess.call(["openssl", "pkeyutl", "-verify", "-in", ec_sign_info_sha256, "-sigfile", ec_binary_sign_file, "-pubin", "-inkey", public_key_file_path, "-keyform", "PEM"]) os.remove(ec_sign_info_file) os.remove(ec_sign_info_sha256) os.remove(ec_binary_sign_file) print("verify_ecdsa_sign result:", "succ" if ret == 0 else "fail") if len(sys.argv) < 2: print("Usage:") print("python mmiot_ecdsa_sign.py gen_ecdsa_key <private_key_file_path> <public_key_file_path>") print("python mmiot_ecdsa_sign.py gen_ecdsa_sign <product_id> <sn> <private_key_file_path> <sign_file_path>") print("python mmiot_ecdsa_sign.py verify_ecdsa_sign <product_id> <sn> <public_key_file_path> <sign_file_path>") exit() if sys.argv[1] == "gen_ecdsa_key": gen_ecdsa_key(sys.argv[2], sys.argv[3]) elif sys.argv[1] == "gen_ecdsa_sign": gen_ecdsa_sign(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) elif sys.argv[1] == "verify_ecdsa_sign": verify_ecdsa_sign(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) else: print("Usage:") print("python mmiot_ecdsa_sign.py gen_ecdsa_key <private_key_file_path> <public_key_file_path>") print("python mmiot_ecdsa_sign.py gen_ecdsa_sign <product_id> <sn> <private_key_file_path> <sign_file_path>") print("python mmiot_ecdsa_sign.py verify_ecdsa_sign <product_id> <sn> <public_key_file_path> <sign_file_path>") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值