从零实现文件加密、解密(基础原理演示)

有一个做底端嵌入式的朋友请求帮忙做一个加密、解密的功能。 蓝牙一个广播包是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")
}

效果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐墨123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值