当前位置:   article > 正文

常用的加密方式(md5,base64,url,AES对称加密,RSA非对称加密)_url及base64加密工具

url及base64加密工具

md5加密方式

一种被广泛使用的单向哈希算法不可逆,可以产生出一个128位(16字节的散列值

crypto
import { createHash } from 'crypto';
//十六进制的字符串形式
static hexDigits: string[] = [
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
  ];

//md5加密方式
  static encodeByMD5(originString: string): string {
    if (originString) {
      try {
        //创建实例,指定md5为哈希加密方式
        const hash = createHash('md5');
        //返回值为buffer类型的字节数组(第一个值为要加密的字符串,第二个规定为utf8形式)
        const results = hash.update(originString, 'utf8').digest();
        //调用方法将字节数组转为字符串
        const resultString: string = this.byteArrayToHexString(results);

        return resultString;
      } catch (ex) {
        console.error(ex);
      }
    }

    return '';
  }

//接收一个buffer类型的字节数组,返回值为string类型
  static byteArrayToHexString(b: Buffer): string {
    let resultSb = '';
      //for循环遍历字节数组
    for (let i = 0; i < b.length; i++) {
        //调用方法进行转换
      resultSb += this.byteToHexString(b[i]);
    }

    return resultSb;
  }

  static byteToHexString(b: number): string {
      //先对数字进行了处理,如果它是一个负数,则将其调整为一个无符号的 8 位整数(因为 JavaScript 中的数字是以 IEEE 754 格式的浮点数来存储的,所以需要显式地转成 8 位整数)。然后,分别计算该数的个位和十位上的十六进制值,将其转换为对应的字符,拼接起来成为一个 2 位的十六进制字符串返回。
    let n: number = b;
    if (n < 0) {
      n = 256 + n;
    }
    const d1 = n / 16;	//个位十六进制值
    const d2 = n % 16;	//十位十六进制值

      //转为整数类型
    const d3 = parseInt(d1.toString());
    const d4 = parseInt(d2.toString());

      //两位十六进制字符串
    return this.hexDigits[d3] + this.hexDigits[d4];
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
static md5(source: string): string {
    const hash = createHash('md5');
    hash.update(source, 'utf8');
    return hash.digest('hex');//上面的实现可以通过传递一个hex直接实现
  }
  • 1
  • 2
  • 3
  • 4
  • 5
crypto-js

下载依赖:

npm install crypto-js
  • 1
import * as CryptoJS from 'crypto-js';

static md5(source:string){
	//md5加密
	const wordArray = CryptoJS.enc.Utf8.parse('2022JueJin')
	CryptoJS.MD5(wordArray).toString();
	
	//base64
	const base64 = CryptoJS.enc.Base64.stringify(CryptoJS.MD5('2022JueJin'))
    const base64two = Buffer.from(source).toString('base64'),
	//第一种加密出来是只有base64加密
    //第二种多加了一层url加密
}

//url加密实现原理
static urlEncode(str: string): string {
    let encodedStr = encodeURIComponent(str);
    encodedStr = encodedStr.replace(/[-_.!~*'()]/g, (char) => {
      const hexCode = char.charCodeAt(0).toString(16).toUpperCase();
      return `%${hexCode}`;
    });
    return encodedStr;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

tips:哈希算法:(md5的底层原理)

这里只做简单的介绍,有兴趣可以深入了解.

哈希法又称为:散列法,杂凑法,关键字地址计算法,相对应的表称为哈希表,散列表或杂凑表.

基本思想:首先在元素的关键字k和元素的存储位置p之间简历一个对应关系H,使得p=H(k),H称为焊锡函数,创建哈希表时,把关键字为k的元素直接存入地址为H(k)的单元.查找时候利用哈希函数计算出位置.

哈希函数构造方法

数字分析法,平方取中法,分段叠加法,除留余数法,伪随机数法

解决哈希冲突的方法:

开放定址法,再哈希法,链地址法,建立公共溢出区

举个简单的例子:(简单通俗的理解一下哈希存储和查找元素)

已知一组关键字序列(19,14,23 ,01 ,68 ,20,84 ,27,55,11,10,79),给出按哈希函数H(key)=key%13和线性探测处理冲突构造所得哈希表ht[0…15]。

如图所示。其中,每个关键字下面带圈的数字,是放置该关键字时所进行的地址计算次数,或者说是放置该关键字时所进行的关键字比较次数(同时也是查找该关键字时所进行的关键字比较次数)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgbeNhEZ-1681466387252)(C:\Users\57429\AppData\Roaming\Typora\typora-user-images\1681380409994.png)]

查找19时,通过计算H(19)= 6,ht[6]. key非空且值为19查找成功则查我关键字19,仅需要计算一次地址就可以找到。 在找14时,通过计算H(14)=1,ht[1],key非空且值为14查找成功,查找 23时,通过计算H(23)= 10,ht[ 10]. key非空且值为23查找成功,则查找关键字23.仅需要计算一次地址就可以找到。同样,查找关键字68 ,20,11 ,均需要计算一次地址就可以找到。

查找关键字01时,通过计算H(01)= 1,ht[1].key非空且值为14≠01,则找第一次冲突处理后的地址h=(1+1)% 16=2,此时,ht[2]. key非空且值为01,查找成功,因此查找关键字01时,需要计算二次地址才可以找到。

查找关键字55时,通过计算H(55)=3,h[3. key非空且值为68≠55,则找第一次冲突处 h=(3+1)%16=4.此时,ht[4].key非空且值为27≠55,则查找两次冲突后处理地址为h2=(3+2)%16=5,ht[5].key非空且值为55,查找成功,因此查找55,需要计算三次.


AES加密

AES为高级加密标准(Advanced Encryption Standard,AES),是一种对称加密算法,根据加密算法不同,密钥的长度和IV的长度不同,aes-128-cbc,那么cipher文件中的key和iv必须为16字节,aes-192-cbc key和iv必须为24字节,aes-256-cbc key和iv必须为32字节。

import * as CryptoJS from 'crypto-js';

const message = CryptoJS.enc.Utf8.parse('JueJin2022')
const secretPassphrase = CryptoJS.enc.Utf8.parse('0123456789asdfgh')
const iv = CryptoJS.enc.Utf8.parse('0123456789asdfgh')

const encrypted = CryptoJS.AES.encrypt(message, secretPassphrase, {
  mode: CryptoJS.mode.CBC,
  paddding: CryptoJS.pad.Pkcs7,
  iv
}).toString()

console.log(encrypted)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

使用aes-128-cbc加密和解密字符串123456,密钥为:nnnnnnnnnnnnnnnn

let a2 = require("crypto");

//aes128加密
function aes128encrypt(data, key){
    let t1 = a2.createCipheriv('aes-128-cbc',key, "nnnnnnnnnnnnnnnn");
    let crypted = t1.update(data,'utf-8','hex');
    crypted += t1.final('hex');
    return crypted;
}

//aes128解密
function unaes256encrypt(crypted,key){
    let t2 = a2.createDecipheriv('aes-128-cbc', key, "nnnnnnnnnnnnnnnn");
    let decrypted = t2.update(crypted, 'hex', 'utf8');
    decrypted += t2.final('utf8');
    return decrypted;
}

输出结果为123456
console.log(unaes256encrypt(aes256encrypt("123456","nnnnnnnnnnnnnnnn"),"nnnnnnnnnnnnnnnn"));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

CryptoJS.AES.encrypt() 可以传入 3 个参数: 第 1 个为需要加密的明文; 第 2 个是秘钥,长度可以是 128、192 或 256 bit; 第 3 个为一个配置对象,可以添加一些配置。常见的配置属性有:

  • mode:加密模式。默认为 CBC,还支持且常用的是 ECB。CBC 模式需要偏移向量 iv,而 ECB 不需要。
  • paddding:填充方式。默认为 Pkcs7;
  • iv:偏移向量 ;

注意,明文、秘钥和偏移向量一般先用诸如 CryptoJS.enc.Utf8.parse() 转成 WordArray 对象再传入,这样做得到结果与不转换直接传入是不一样的。


RSA加密

RSA 是一种非对称加密算法,使用公钥(公开密钥PK)加密、私钥(秘密密钥SK)解密;

import * as crypto from 'crypto';

export class RSA {
  private _privateKey: string;
  private _publicKey: string;
  private keySize: number;

  constructor(keySize: number) {
    //RSA允许你选择公钥的大小。512位的密钥被视为不安全的;768位的密钥不用担心受到除了国家安全管理(NSA)外		的其他事物的危害
    this.keySize = keySize || 1024;
    //从 node.js 的 v10.12.0 开始,可以使用内部模块 crypto.generateKeyPairSync 方法生成公私钥
    const keyPair = crypto.generateKeyPairSync('rsa', {
      modulusLength: this.keySize,
      //配置加密参数(填充方式,加密模式等)
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem',
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
      },
    });
    this._privateKey = keyPair.privateKey;
    this._publicKey = keyPair.publicKey;
  }

  // 设置 privateKey 的 setter 方法
  set privateKey(privateKey: string) {
    this._privateKey = privateKey;
  }

  // 设置 publicKey 的 setter 方法
  set publicKey(publicKey: string) {
    this._publicKey = publicKey;
  }

  // 获取 privateKey 的 getter 方法
  get getPrivateKey(): string {
    return this._privateKey;
  }

  // 获取 publicKey 的 getter 方法
  get getPublicKey(): string {
    return this._publicKey;
  }

  // 加密
  encrypt(data): string {
    const buffer = Buffer.from(data, 'utf-8');
    const encryptedBuffer = crypto.publicEncrypt(this._publicKey, buffer);
    return encryptedBuffer.toString('base64');
  }

  // 解密
  decrypt(data): string {
    const buffer = Buffer.from(data, 'base64');
    const decryptedBuffer = crypto.privateDecrypt(this._privateKey, buffer);
    return decryptedBuffer.toString('utf-8');
  }
}

该示例中,定义了一个 RSA 类,通过 crypto 模块来实现 RSA 加密算法。构造函数中,设置了加密密钥的长度,同时使用 crypto.generateKeyPairSync() 方法来生成公钥和私钥。其中,modulusLength 参数表示密钥的长度,publicKeyEncoding 和 privateKeyEncoding 分别表示公钥和私钥的格式。

在 encrypt 方法中,将输入的字符串转换为 Buffer 对象,并使用 crypto.publicEncrypt() 方法进行加密,传入公钥进行加密。最后将加密后的结果转换为指定编码方式的字符串并返回。

在 decrypt 方法中,先将输入的字符串转换为 Buffer 对象,然后使用 crypto.privateDecrypt() 方法进行解密,传入私钥进行解密。最后将解密后的结果转换为指定编码方式的字符串并返回。

需要注意的是,加密和解密使用的是不同的公钥和私钥。在使用时,需要新建一个 RSA 实例,并将其公钥用于加密,私钥用于解密。同时也需要注意密钥的保密性,确保密钥不会泄露。

//使用方法
async Rsa(req) {
    const rsa = new RSA(1024);
    console.log(rsa, 'rsa1');
    const pub = rsa.getPublicKey;
    const pri = rsa.getPrivateKey;
    console.log(pub, 'pub');
    console.log(pri, 'pri');
    rsa.privateKey = 'pri';
    rsa.publicKey = 'pub';
    console.log(rsa, 'rsa2');

    //加密
    const b = rsa.encrypt('1234');
    //解密
    const a = rsa.decrypt(b);

    return { a, b };
 }

//以上封装的类RSA基本上就是node-rsa的实现原理,传参方面略有不同,更深层次可以查看源码.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

node-rsa

npm install node-rsa
  • 1
import * as RSA from 'node-rsa';
import * as crypto from 'crypto';

//如果不指定导出格式,公钥默认是pkcs8,私钥是pkcs1
const key = new NodeRSA({b: 512});//生成512位秘钥
let pubkey = key.exportKey('pkcs8-public');//导出公钥
let prikey = key.exportKey('pkcs8-private');//导出私钥
//生成两个实例
let pubKey = new NodeRSA(pubKey,'pkcs8-public');//导入公钥
let priKey = new NodeRSA(priKey,'pkcs8-private');//导入私钥
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
 //   --- RSA ---
  //   rsa加密
  static rsaEncode(code: string) {
    const privateRSA = new RSA(Encrypt.RSA.PRIVATE_KEY);
    return privateRSA.encrypt(code, 'base64');
  }

  //   rsa解密
  static rsaDecode(code: string) {
    const privateRSA = new RSA(Encrypt.RSA.PRIVATE_KEY);
    return privateRSA.decrypt(code, 'utf8');
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

看到了一个很好的C/S的设计思路:

  1. 服务端计算出一对秘钥pub/pri。将私钥保密,将公钥公开。
  2. 客户端请求服务端时,拿到服务端的公钥pub。
  3. 客户端通过AES计算出一个对称加密的秘钥X。 然后使用pub将X进行加密。
  4. 客户端将加密后的密文发送给服务端。服务端通过pri解密获得X。
  5. 然后两边的通讯内容就通过对称密钥X以对称加密算法来加解密。

其他加密方式

字符串SHA256加密

SHA256是安全散列算法(Secure Hash Algorithm),对于任意长度的消息,SHA256都会产生一个256bit长的哈希值,长度为32个字节,通常用一个长度为64的十六进制字符串来表示

let a1 = require("crypto-js");
let a2 = require("crypto");

let res3 = a1.SHA256("123456").toString();
let res4 = a2.createHash("sha256").update("123456").digest('hex');

//使用res3或res4都可以,加密结果一样
console.log(res3);
console.log(res4);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

字符串HMac加密

let a1 = require("crypto-js");
let a2 = require("crypto");

let res5 = a1.HmacMD5("123456", "apple").toString();
let res6 = a2.createHmac("md5","apple").update("123456").digest('hex');

//使用res5或res6都可以,加密结果一样
console.log(res5);
console.log(res6);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/470059
推荐阅读
相关标签
  

闽ICP备14008679号