有一个做底端嵌入式的朋友请求帮忙做一个加密、解密的功能。 蓝牙一个广播包是32byte,因此不可能用rsa等加密算法。
这里用异或进行加密
加密、解密的本质思想是数据的可逆置换(军事上面的无线电密码本,就是置换符号)。 置换符号可以是静态、也可以是动态, 置换算法,是依据高等数学的对称曲线关系(x轴、y轴,或某个直线对称,即可实现加密、解密), 区别在于解密时cpu的计算时间,解密时cpu消耗的时间不一样。
本文是原理性质的讲解,本文作者也不擅长高等数学,因此用简单的加密方法,主要是讲清楚实现一个加密算法的原理。
一、c语言版本:
原理:
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
上代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 密钥
const unsigned char PUB[32] = {
0x01, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x02, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x03, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x04, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
};
// 加密、解密(加密、解密函数的实现,可以用其它对称曲线,例如椭圆曲线、抛物线进行加密)
void en_de_cryption(unsigned char *data, int len, unsigned char *out) {
unsigned char i = 0;
for(i = 0; i < len; i++)
{
out[i] = data[i] ^ PUB[i];
}
}
int main()
{
int i;
// 原始数据
char p_data[16] = {"Hello World!"};
// buf存放解密、加密数据
char Encrypt1[16] = {0}, Decode1[16] = {0};
// 调用(奇数次)加密
en_de_cryption(p_data, strlen(p_data), Encrypt1);
// 调用(偶数次)解密
en_de_cryption(Encrypt1, strlen(p_data), Decode1);
// 打印原始数据、加密数据、解密数据
printf("Initial date: %s\n",p_data);
printf("Encrypt1 date: %s\n",Encrypt1);
printf("Decode1 date: %s\n",Decode1);
return 0;
}
执行效果:
root@jack-VirtualBox:~# ./a.out
Initial date: Hello World!
Encrypt1 date: IcǶHpj;
Decode1 date: Hello World!
root@jack-VirtualBox:~#
二、c语言升级版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/*
*function description: Encrypt data
*data: the raw data
*len: length of raw data
*out: The encrypted data
*key: secret key
* */
int en_cryption_dynamic(unsigned char *data, int len, unsigned char *out, unsigned char *key) {
unsigned char *pkey= key;
unsigned char i = 0;
unsigned char *pd = data;
memcpy(out, pkey, 4);
for(i = 0; i < len; i++)
{
pd = &out[i % 4];
out[4 + i] = data[i] ^ pd[i];
}
return 4 + len;
}
/*
*function description: Decrypt the data
*len: length of data
*out: The data after decryption
* */
void de_cryption_dynamic(unsigned char *data, int len, unsigned char *out) {
unsigned char i = 0;
unsigned char *pd = data;
for(i = 0; i < len - 4; i++)
{
pd = &data[i % 4];
out[i] = data[4 + i] ^ pd[i];
}
}
int my_rand(unsigned char *buf, int nrand){
int i = 0;
srand((unsigned int)time(0));
for ( ; i < nrand; ++i) {
buf[i] = rand() % 0xff + 1;
}
return 0;
}
int main()
{
int i;
unsigned char key[4] = {0x01, 0x02, 0x03, 0x04};
// 原始数据
char p_data[32] = {"Hello World!"};
// buf存放解密、加密数据
char Encrypt1[32] = {0}, Decode1[32] = {0};
// 获取随机数
my_rand(key, 4);
for (i=0; i<4; i++) {
printf(" %d", key[i]);
}
printf("\r\n");
// 动态加密
int len_1 = 0;
len_1 = en_cryption_dynamic(p_data, strlen(p_data), Encrypt1, key);
// 动态解密
de_cryption_dynamic(Encrypt1, len_1, Decode1);
// 打印原始数据、加密数据、解密数据
printf("Initial date: %s\r\n",p_data);
printf("Encrypt1 date: %s\r\n",Encrypt1);
printf("Decode1 date: %s\r\n",Decode1);
return 0;
}
三、golang版本:
package main
import "fmt"
var PUB = [32]byte{
0x01, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x02, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x03, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x04, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
}
func en_de_cryption(data []byte) []byte {
for i, _ := range data {
data[i] ^= PUB[i%32]
}
return data
}
func main() {
data := []byte("hello world")
fmt.Printf("%s\n", data)
fmt.Printf("%s\n", en_de_cryption(data))
fmt.Printf("%s\n", en_de_cryption(data))
}
运行:
四、golang版本-文件加密、文件解密:
文件加密,就需要在加密文件中写入必要的状态信息、公钥等信息:
加密文件的存储格式为:加密头的length(4byte)、加密头(512-4) byte、密文
先简单设计,后面有空对完整性、性能进行优化,然后实现一点业务功能(例如结合网络传输协议对内容快速加密、对象存储底层加密)
本项目gitee.com仓库地址: git@gitee.com:free_source_golang/lightweight-encrypted-file.git
package main
import (
"crypto/sha256"
"encoding/json"
"errors"
"io"
"os"
"path/filepath"
"reflect"
)
var PUB = [32]byte{
0x01, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x02, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x03, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
0x04, 0x06, 0xa5, 0x5a, 0x79, 0xae, 0x1f, 0x7c,
}
type header struct {
Magic uint64 `json:"magic"`
Length int64 `json:"length"`
Sha256 [32]byte `json:"sha256"`
RawName string `json: "rawname"`
nb int
np int
pub []byte
reader io.Reader
}
func (h *header) Read(p []byte) (n int, err error) {
h.reader.Read(p)
h.np = h.nb
for i, _ := range p {
p[i] ^= h.pub[h.np%32]
h.np += 1
}
return int(h.np - h.nb), nil
}
func en_de_cryption(data []byte) []byte {
for i, _ := range data {
data[i] ^= PUB[i%32]
}
return data
}
func file_en_cryption(path string, key string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
header := &header{Magic: 0xbadbeef0, pub: []byte(key)}
header.Sha256 = sha256.Sum256([]byte(key))
header.RawName = filepath.Base(path)
if fileinfo, err := f.Stat(); err == nil {
header.Length = fileinfo.Size()
} else {
return nil, err
}
tempFile := os.File{}
defer func() {
tempFile.Close()
}()
if File, err := os.CreateTemp("", path+".tscz"); err == nil {
defer func() {
File.Close()
}()
if data, err := json.Marshal(header); err == nil {
metadataLength := len(data)
metadataBuf := make([]byte, 4)
metadataBuf[0] = byte(metadataLength & 0xff)
metadataBuf[1] = byte(metadataLength >> 8 & 0xff)
metadataBuf[2] = byte(metadataLength >> 16 & 0xff)
metadataBuf[3] = byte(metadataLength >> 24 & 0xff)
File.Write(metadataBuf)
buffer := make([]byte, 512-4)
copy(buffer, data)
File.Write(buffer)
}
s := make([]byte, 4096)
for {
if nr, err := f.Read(s[:]); err == nil && nr > 0 {
// 打印原始数据
//fmt.Println(string(s))
s = s[:nr]
header.np = header.nb
for i, _ := range s {
s[i] ^= header.pub[header.np%len(header.pub)]
header.np += 1
}
File.Write(s)
} else {
break
}
}
os.Rename(File.Name(), path+".tscz")
}
return nil, nil
}
func SliceEquals(a, b interface{}) bool {
_a := reflect.ValueOf(a)
_b := reflect.ValueOf(b)
if _a.Len() != _b.Len() {
return false
}
for i := 0; i < _a.Len(); i++ {
if _a.Index(i).Interface() != _b.Index(i).Interface() {
return false
}
}
return true
}
func file_de_cryption(path string, key string) ([]byte, error) {
if filepath.Ext(path) != ".tscz" {
return nil, errors.New("ext name of de cryption should be .tscz")
}
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
header := &header{pub: []byte(key)}
buf := make([]byte, 512)
if n, err := f.Read(buf); err == nil && n > 0 {
metadataLength := buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24
if err := json.Unmarshal(buf[4:4+metadataLength], &header); err != nil {
return nil, err
}
} else {
return nil, err
}
if header.Magic != 0xbadbeef0 {
return nil, errors.New("unidentified by this tool")
}
if !SliceEquals(header.Sha256, sha256.Sum256([]byte(key))) {
return nil, errors.New("invalid password")
}
tempFile := os.File{}
defer func() {
tempFile.Close()
}()
if File, err := os.CreateTemp("", path); err == nil {
defer func() {
File.Close()
}()
f.Seek(512, os.SEEK_SET)
s := make([]byte, 4096)
for {
if nr, err := f.Read(s[:]); err == nil && nr > 0 {
s = s[:nr]
header.np = header.nb
for i, _ := range s {
s[i] ^= header.pub[header.np%len(header.pub)]
header.np += 1
}
File.Write(s)
// 打印解密后的数据
//fmt.Println(string(s))
} else {
break
}
}
os.Rename(File.Name(), header.RawName+".bak")
}
return nil, nil
}
func main() {
// 数据加密、解密
//data := []byte("hello world")
//fmt.Printf("%s\n", data)
//fmt.Printf("%s\n", en_de_cryption(data))
//fmt.Printf("%s\n", en_de_cryption(data))
// 文件加密、解密
file_en_cryption("file.txt", "nihao")
file_de_cryption("file.txt.tscz", "nihao")
}
效果: