加密算法详尽指南

Spring-_-Bear 的 CSDN 博客导航

一、引言

在当今数字化时代,数据已成为最具价值的资产之一,而保护这些数据免受未授权访问、篡改和盗窃的需求比以往任何时候都更加迫切。加密技术作为信息安全的核心支柱,为数据提供了一层强大的保护,确保敏感信息在存储和传输过程中保持机密性和完整性。简单来说,加密是一种将可读数据(明文)转换为不可读格式(密文)的过程,使得只有拥有正确密钥的人能够恢复原始信息。这一基本概念虽然简单,但其实施方式却极其复杂和多样化,形成了当今密码学的广阔领域。

加密的重要性不容忽视。随着越来越多的个人和企业将关键数据迁移到云存储,通过互联网进行敏感通信,并依赖数字系统处理日常事务,保护这些数据免受恶意行为者侵害的需求变得尤为迫切。没有强大的加密,我们的数字通信和交易将容易受到各种形式的网络威胁,包括身份盗窃、数据泄露和金融欺诈。加密技术的应用范围广泛,从保护个人隐私(如电子邮件和消息应用)到维护国家安全和商业机密,几乎涵盖了数字世界的方方面面。

加密技术的历史可以追溯到古代,但现代加密技术,特别是计算机时代的加密算法,经历了从简单的替换密码到复杂的数学算法的漫长发展过程。随着计算能力的飞速提升,加密算法也不断演进,以应对日益复杂的网络安全威胁。

二、发展历史

  1. 早期加密方法:在计算机时代之前,加密主要依靠机械和手工方法。例如,二战期间使用的 Enigma 机器就是一个著名的加密设备,它通过一系列的转子和电线来实现加密。虽然这些早期方法在当时具有一定的安全性,但它们往往容易被破解,且效率低下。

    在这里插入图片描述

    艾伦·麦席森·图灵(英语:Alan Mathison Turing1912-06-23 ~ 1954-06-07),英国计算机科学家、数学家、逻辑学家、密码分析学家、理论生物学家,“计算机科学之父”、“人工智能之父”,英国皇家学会院士。

    • 1935 年当选为剑桥大学国王学院研究员;

    • 1936 年提出被称为图灵机的逻辑机通用模型;

    • 1938 年获普林斯顿大学博士学位;

    • 1939 年开始在英国军方工作,期间破解德国密码系统恩尼格玛密码机和金枪鱼密码机,加速了盟军取得了二战的胜利;

    • 1946 年获大英帝国勋章;

    • 1945 年至 1948 年在伦敦泰丁顿国家物理实验室负责自动计算引擎(ACE)的研究工作;

    • 1948 年任曼彻斯特大学高级讲师、自动数字计算机(Madam)项目的负责人助理;

    • 1949 年任曼彻斯特大学计算机实验室副主任;

    • 1950 年提出机器具备思维的可能性和 “图灵测试” 的概念;

    • 1951 年当选为英国皇家学会院士;

    • 1954 年服用含氰化物的苹果去世,享年 41 岁。

    在这里插入图片描述

    豆瓣电影 Top155 推荐:模仿游戏 The Imitation Game (2014)

  2. 现代加密算法的发展:随着计算机技术的发展,加密算法也进入了数字化时代。1976 年,Diffie(图左)和 Hellman(图右)提出了非对称加密的概念(荣获 2015 年图灵奖),这标志着现代密码学的一个重要里程碑。非对称加密使用一对密钥:一个公钥和一个私钥,使得加密和解密可以由不同的密钥完成。这种方法极大地提高了通信的安全性,因为它允许在不安全的信道上安全地交换密钥。
    在这里插入图片描述

  3. 对称加密算法的演进:对称加密算法也在不断发展。DES(Data Encryption Standard)(数据加密标准)是最早的对称加密算法之一,但它使用 56 位密钥,安全性相对较弱。为了提高安全性,3DES(Triple DES) 被提出,它使用三个 DES 加密步骤,大大增加了破解的难度。随后,AES(Advanced Encryption Standard)(高级加密标准)被开发出来,它使用 128 位、192 位或 256 位密钥,提供了更高的安全性,并且被广泛采用。

  4. 哈希函数和数字签名:除了加密算法,哈希函数和数字签名也是现代密码学的重要组成部分。哈希函数将数据映射到固定长度的哈希值,用于数据完整性检查和密码存储等场景,而数字签名允许验证消息的来源和完整性。

    在这里插入图片描述

三、分类与原理

  1. 对称加密与非对称加密:加密算法主要分为对称加密和非对称加密两大类。对称加密使用相同的密钥进行加密和解密,而非对称加密则使用一对不同的密钥:公钥和私钥。对称加密速度快,适合大量数据的加密,而非对称加密则在密钥分发和数字签名方面具有优势。

  2. 哈希函数与消息认证码:哈希函数和消息认证码(MAC(Message Authentication Code))是两种不同的数据验证机制。哈希函数(无需密钥)将输入数据映射到固定长度的输出,且具有单向性和碰撞抗性。消息认证码(需要密钥)则结合了加密和哈希函数,用于验证消息的完整性和来源的真实性。

  3. 加密算法的基本原理:加密算法的基本原理是将明文通过一定的数学变换转换为密文,使得只有拥有正确密钥的人才能恢复原始信息。这些算法通常基于复杂的数学问题,如大整数分解、离散对数等,使得在没有密钥的情况下破解加密变得极其困难。

加密算法分类特点
对称加密加解密使用相同密钥
加密速度快,适合大量数据加密
非对称加密公钥加密,私钥解密
计算开销大,密钥分发存在天然优势
哈希函数将输入数据映射到固定长度输出
无需密钥、单向不可逆、抗碰撞性
消息认证码哈希函数 + 对称加密
数字签名哈希函数 + 非对称加密

四、常见加密算法

加密算法填充模式:加密算法在处理数据时,常常需要确保数据长度符合特定的要求,这通常是因为加密算法需要处理固定大小的数据块。为了满足这一要求,当数据长度不满足这一要求时,就需要使用填充模式(Padding Scheme)。填充模式是在数据的末尾添加一些额外的信息,使得数据长度达到一个合适的长度,以便进行加密。

填充模式填充方式优点缺点
Zero Padding直接在数据的末尾添加零(0x00),直到达到所需的长度最简单的填充方法,简单易实现如果原始数据本身以 0 结尾,可能会导致数据与填充部分难以区分
PKCS#5/7填充的字节都是相同的值,该值等于需要填充的字节数。例如,如果需要填充 5 个字节,那么这 5 个字节的值都是 0x05常用的填充模式,可以明确知道填充了多少字节,便于解填充如果原始数据本身以 1 结尾,且填充值为 1,可能会与数据本身混淆
PKCS#1 v1.5主要用于 RSA 加密,使用一个固定的填充模式,包括一些特定的字节和随机数据提供了更高的安全性比较复杂,且不适用于所有类型的加密算法
ANSI X.923填充字节除了最后一个字节外,其余字节都填充为零。最后一个字节表示填充的字节数相对简单,且可以明确知道填充了多少字节如果数据本身以 0 结尾,可能会导致数据与填充部分难以区分
ISO 10126除了最后一个字节外,其余填充字节都是随机数据。最后一个字节表示填充的字节数随机性增加了安全性需要生成随机数,增加了实现的复杂性
ISO/IEC 7816-4主要用于智能卡中,填充字节除了最后一个字节外,其余字节都是 0x00。最后一个字节表示填充的字节数适用于智能卡等特定场景应用场景有限
  1. PKCSPublic Key Cryptography Standards
  2. ANSIAmerican National Standards Institute
  3. ISOInternational Organization for Standardization
  4. IECInternational Electrotechnical Commission
// padding 填充函数 (PKCS5/PKCS7)
func padding(src []byte, blockSize int) []byte {
	paddingSize := blockSize - len(src)%blockSize
	padText := bytes.Repeat([]byte{byte(paddingSize)}, paddingSize)
	return append(src, padText...)
}

// unPadding 去填充函数
func unPadding(src []byte) []byte {
	length := len(src)
	unPaddingSize := int(src[length-1])
	return src[:(length - unPaddingSize)]
}

4.1 对称加密

在这里插入图片描述

  1. DES(Data Encryption Standard)DES 是最早的对称加密算法之一,使用 56 位密钥将 64 位明文块加密为 64 位密文块。由于其密钥长度较短,安全性相对较弱,已被 AES 取代。

    // desEncrypt DES 加密
    func desEncrypt(key, iv, plaintext []byte) ([]byte, error) {
    	block, err := des.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockSize := block.BlockSize()
    	plaintext = padding(plaintext, blockSize)
    	blockMode := cipher.NewCBCEncrypter(block, iv)
    	ciphertext := make([]byte, len(plaintext))
    	blockMode.CryptBlocks(ciphertext, plaintext)
    
    	return ciphertext, nil
    }
    
    // desDecrypt DES 解密
    func desDecrypt(key, iv, ciphertext []byte) ([]byte, error) {
    	block, err := des.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockMode := cipher.NewCBCDecrypter(block, iv)
    	plaintext := make([]byte, len(ciphertext))
    	blockMode.CryptBlocks(plaintext, ciphertext)
    	plaintext = unPadding(plaintext)
    
    	return plaintext, nil
    }
    
  2. 3DES(Triple DES)3DES 使用三个 DES 加密步骤,大大增加了破解的难度。它使用两个或三个不同的密钥,提供了比单 DES 更高的安全性。

    // tripleDesEncrypt 3DES 加密
    func tripleDesEncrypt(key, iv, plaintext []byte) ([]byte, error) {
    	block, err := des.NewTripleDESCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockSize := block.BlockSize()
    	plaintext = padding(plaintext, blockSize)
    	blockMode := cipher.NewCBCEncrypter(block, iv)
    	ciphertext := make([]byte, len(plaintext))
    	blockMode.CryptBlocks(ciphertext, plaintext)
    
    	return ciphertext, nil
    }
    
    // tripleDesDecrypt 3DES 解密
    func tripleDesDecrypt(key, iv, ciphertext []byte) ([]byte, error) {
    	block, err := des.NewTripleDESCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockMode := cipher.NewCBCDecrypter(block, iv)
    	plaintext := make([]byte, len(ciphertext))
    	blockMode.CryptBlocks(plaintext, ciphertext)
    	plaintext = unPadding(plaintext)
    
    	return plaintext, nil
    }
    
  3. AES(Advanced Encryption Standard)AES 是目前最常用的对称加密算法之一,使用 128 位、192 位或 256 位密钥将 128 位明文块加密为 128 位密文块。AES 基于有限域上的字节替代、行移位、列混淆和轮密钥加等操作,提供了高强度的安全性。

    // aesEncrypt AES 加密
    func aesEncrypt(key, iv, plaintext []byte) ([]byte, error) {
    	block, err := aes.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockSize := block.BlockSize()
    	plaintext = padding(plaintext, blockSize)
    	blockMode := cipher.NewCBCEncrypter(block, iv)
    	ciphertext := make([]byte, len(plaintext))
    	blockMode.CryptBlocks(ciphertext, plaintext)
    
    	return ciphertext, nil
    }
    
    // aesDecrypt AES 解密
    func aesDecrypt(key, iv, ciphertext []byte) ([]byte, error) {
    	block, err := aes.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockMode := cipher.NewCBCDecrypter(block, iv)
    	plaintext := make([]byte, len(ciphertext))
    	blockMode.CryptBlocks(plaintext, ciphertext)
    	plaintext = unPadding(plaintext)
    
    	return plaintext, nil
    }
    
  4. SM4SM4 是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于 2012321 日发布,相关标准为 “GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”。20168 月,成为中国国家密码标准(GB/T 32907-2016)。

    // sm4Encrypt SM4 加密
    func sm4Encrypt(key, iv, plaintext []byte) ([]byte, error) {
    	block, err := sm4.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockSize := block.BlockSize()
    	plaintext = padding(plaintext, blockSize)
    	blockMode := cipher.NewCBCEncrypter(block, iv)
    	ciphertext := make([]byte, len(plaintext))
    	blockMode.CryptBlocks(ciphertext, plaintext)
    
    	return ciphertext, nil
    }
    
    // sm4Decrypt SM4 解密
    func sm4Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
    	block, err := sm4.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    
    	blockMode := cipher.NewCBCDecrypter(block, iv)
    	plaintext := make([]byte, len(ciphertext))
    	blockMode.CryptBlocks(plaintext, ciphertext)
    	plaintext = unPadding(plaintext)
    
    	return plaintext, nil
    }
    
算法分组大小密钥长度说明
DES64 位56 位已淘汰(被暴力破解)
3DES64 位168 位DES 的三次迭代,逐渐被弃用
AES128 位128/192/256 位美国国家标准技术研究院认证标准,硬件加速支持
SM4128 位128 位国密标准,安全性高

4.2 非对称加密

在这里插入图片描述

  1. RSA(Rivest–Shamir–Adleman algorithm)RSA 是非对称加密算法的代表,基于大整数分解的数学难题。它使用一个公钥和一个私钥,公钥用于加密,私钥用于解密。RSA 算法广泛应用于数据加密、数字签名和密钥交换等领域。

    func generateRSAKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
    	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    	if err != nil {
    		return nil, nil, err
    	}
    	return privateKey, &privateKey.PublicKey, nil
    }
    
    func rsaEncrypt(publicKey *rsa.PublicKey, plaintext []byte) ([]byte, error) {
    	return rsa.EncryptOAEP(
    		sha256.New(),
    		rand.Reader,
    		publicKey,
    		plaintext,
    		nil,
    	)
    }
    
    func rsaDecrypt(privateKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
    	return rsa.DecryptOAEP(
    		sha256.New(),
    		rand.Reader,
    		privateKey,
    		ciphertext,
    		nil,
    	)
    }
    
    func rsaSign(privateKey *rsa.PrivateKey, message []byte) ([]byte, error) {
    	hashed := sha256.Sum256(message)
    	return rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
    }
    
    func rsaVerify(publicKey *rsa.PublicKey, message, signature []byte) error {
    	hashed := sha256.Sum256(message)
    	return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)
    }
    
  2. DSA(Digital Signature Algorithm)DSA 是一种基于离散对数的困难性的非对称加密算法。DSA 算法的安全性依赖于离散对数的难度,目前已经有 1024 位的 DSA 公钥被成功破解,因此建议使用 2048 位或以上的密钥长度。

    func generateDSAKeyPair() (*dsa.PrivateKey, *dsa.PublicKey, error) {
    	privateKey := new(dsa.PrivateKey)
    
    	params := new(dsa.Parameters)
    	if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
    		return nil, nil, err
    	}
    
    	privateKey.PublicKey.Parameters = *params
    	if err := dsa.GenerateKey(privateKey, rand.Reader); err != nil {
    		return nil, nil, err
    	}
    
    	return privateKey, &privateKey.PublicKey, nil
    }
    
    func dsaSign(privateKey *dsa.PrivateKey, message []byte) ([]byte, error) {
    	r, s, err := dsa.Sign(rand.Reader, privateKey, message)
    	if err != nil {
    		return nil, err
    	}
    
    	signature := make([]byte, 40)
    	rBytes := r.Bytes()
    	sBytes := s.Bytes()
    	copy(signature[20-len(rBytes):20], rBytes)
    	copy(signature[40-len(sBytes):40], sBytes)
    
    	return signature, nil
    }
    
    func dsaVerify(publicKey *dsa.PublicKey, message, signature []byte) bool {
    	if len(signature) != 40 {
    		return false
    	}
    
    	r := new(big.Int).SetBytes(signature[:20])
    	s := new(big.Int).SetBytes(signature[20:])
    	return dsa.Verify(publicKey, message, r, s)
    }
    
  3. ECC(Elliptic Curve Cryptography)(椭圆曲线加密):ECC 基于椭圆曲线上点的离散对数问题,提供了与 RSA 相同的安全性,但使用更短的密钥长度。这使得 ECC 在计算效率和带宽方面具有优势,特别适合资源受限的环境。

    func generateECCKeyPair() (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) {
    	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    	if err != nil {
    		return nil, nil, err
    	}
    	return privateKey, &privateKey.PublicKey, nil
    }
    
    func eccSign(privateKey *ecdsa.PrivateKey, message []byte) ([]byte, error) {
    	hashed := sha256.Sum256(message)
    	r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashed[:])
    	if err != nil {
    		return nil, err
    	}
    
    	signature := make([]byte, 64)
    	rBytes := r.Bytes()
    	sBytes := s.Bytes()
    	copy(signature[32-len(rBytes):32], rBytes)
    	copy(signature[64-len(sBytes):64], sBytes)
    
    	return signature, nil
    }
    
    func eccVerify(publicKey *ecdsa.PublicKey, message, signature []byte) bool {
    	if len(signature) != 64 {
    		return false
    	}
    
    	hashed := sha256.Sum256(message)
    	r := new(big.Int).SetBytes(signature[:32])
    	s := new(big.Int).SetBytes(signature[32:])
    	return ecdsa.Verify(publicKey, hashed[:], r, s)
    }
    
  4. SM2SM2 椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,包括 SM2-1 椭圆曲线数字签名算法,SM2-2 椭圆曲线密钥交换协议,SM2-3 椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。SM2 算法与 RSA 算法不同的是,SM2 算法是基于椭圆曲线上点群离散对数难题,相对于 RSA 算法,256 位的 SM2 密码强度已经比 2048 位的 RSA 密码强度要高,且运算速度快于 RSA

    import (
    	"github.com/tjfoc/gmsm/sm2"
    )
    
    func generateSM2KeyPair() (*sm2.PrivateKey, *sm2.PublicKey, error) {
    	privateKey, err := sm2.GenerateKey(rand.Reader)
    	if err != nil {
    		return nil, nil, err
    	}
    	return privateKey, &privateKey.PublicKey, nil
    }
    
    func sm2Encrypt(publicKey *sm2.PublicKey, plaintext []byte) ([]byte, error) {
    	return sm2.Encrypt(publicKey, plaintext, rand.Reader, sm2.C1C3C2)
    }
    
    func sm2Decrypt(privateKey *sm2.PrivateKey, ciphertext []byte) ([]byte, error) {
    	return sm2.Decrypt(privateKey, ciphertext, sm2.C1C3C2)
    }
    
    // SM2 签名(原始形式返回 r,s)
    func sm2SignRaw(privateKey *sm2.PrivateKey, message []byte) (*big.Int, *big.Int, error) {
    	defaultUID := []byte("1234567812345678") // 国密标准默认 UID
    	return sm2.Sm2Sign(privateKey, message, defaultUID, rand.Reader)
    }
    
    // SM2签名(返回 64 字节格式)
    func sm2Sign(privateKey *sm2.PrivateKey, message []byte) ([]byte, error) {
    	r, s, err := sm2SignRaw(privateKey, message)
    	if err != nil {
    		return nil, err
    	}
    
    	// 将 r 和 s 转换为固定长度字节(各 32 字节)
    	rBytes := r.Bytes()
    	sBytes := s.Bytes()
    	signature := make([]byte, 64)
    	copy(signature[32-len(rBytes):32], rBytes)
    	copy(signature[64-len(sBytes):64], sBytes)
    
    	return signature, nil
    }
    
    // SM2 验签(接受 r,s 原始形式)
    func sm2VerifyRaw(publicKey *sm2.PublicKey, message []byte, r, s *big.Int) bool {
    	defaultUID := []byte("1234567812345678")
    	return sm2.Sm2Verify(publicKey, message, defaultUID, r, s)
    }
    
    // SM2 验签(接受 64 字节签名)
    func sm2Verify(publicKey *sm2.PublicKey, message, signature []byte) bool {
    	if len(signature) != 64 {
    		return false
    	}
    
    	r := new(big.Int).SetBytes(signature[:32])
    	s := new(big.Int).SetBytes(signature[32:])
    	return sm2VerifyRaw(publicKey, message, r, s)
    }
    
算法密钥长度说明
RSA2048/4096 位基于大整数分解难题(两个大素数相乘很容易,对乘积进行因式分解极其困难); 加密速度慢于对称加密 1000
DSA2048/3072 位基于离散对数难题;生成密钥对速度比 RSA 快,但签名速度比 RSA 慢;主要用于数字签名
ECC256/384 位基于椭圆曲线上点的离散对数问题;相同安全强度下密钥更短(256ECC3072RSA);适合移动 IoT 等资源受限场景
SM2256 位基于 ECC,中国商用密码标准;256SM2 密码强度相当于 2048RSA;运算速度快于 RSA

4.3 哈希算法

在这里插入图片描述

  1. MD5(Message Digest)MD5 是一种广泛使用的哈希函数,将输入数据映射为 128 位的哈希值。然而,MD5 已被发现存在碰撞漏洞,不再推荐用于安全敏感的应用。

    func computeMD5(data []byte) string {
    	hash := md5.New()
    	hash.Write(data)
    	return hex.EncodeToString(hash.Sum(nil))
    }
    
  2. SHA-1(Secure Hash Algorithm)SHA-1 是另一种常见的哈希函数,产生 160 位的哈希值。虽然 SHA-1MD5 更安全,但也有研究表明其可能存在碰撞风险,因此逐渐被 SHA-2SHA-3 取代。

  3. SHA-2SHA-2 是一组哈希函数,包括 SHA-256SHA-384SHA-512 等,分别产生 256 位、384 位和 512 位的哈希值。SHA-2 目前被认为是安全的,广泛应用于各种安全应用中。

    func computeSHA256(data []byte) string {
    	hash := sha256.New()
    	hash.Write(data)
    	return hex.EncodeToString(hash.Sum(nil))
    }
    
  4. SHA-3SHA-3 是最新一代的哈希函数,基于 Keccak 算法,提供了与 SHA-2 相同的安全级别,但采用了不同的设计结构。SHA-3 旨在作为 SHA-2 的后继,提供更强的安全性。

  5. SM3SM3 适用于商用密码应用中的数字签名和验证,是在 SHA-256 基础上改进实现的一种算法,其安全性和 SHA-256 相当。SM3MD5 的迭代过程类似,也采用 Merkle-Damgard 结构。消息分组长度为 512 位,摘要值长度为 256 位。

    import (
    	"github.com/tjfoc/gmsm/sm3"
    )
    
    func computeSM3(data []byte) string {
    	hash := sm3.New()
    	hash.Write(data)
    	return hex.EncodeToString(hash.Sum(nil))
    }
    
算法输出长度说明
MD532 位存在碰撞漏洞,不再推荐使用
SHA-1160 位存在碰撞风险,逐渐被 SHA-2 取代
SHA-2256/384/512 位安全(比特币挖矿核心算法)
SHA-3224/256/384/512 位最新 NIST 标准,抗量子计算特性
SM3256 位中国商用标准

4.4 消息认证码

MAC(Message Authentication Code),消息认证码结合了加密和哈希函数,用于验证消息的完整性和来源的真实性。常见的 MAC 算法包括 HMAC(基于哈希的 MAC)和 UMAC(通用 MAC)等。

HMAC 是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用哈希算法(MD5SHA1 等),以一个密钥和一个消息为输入,生成一个消息摘要作为输出。

HMAC 使用发送方和接收方都有的 key 进行计算,而没有这把 key 的第三方,则是无法计算出正确的散列值的,这样就可以防止数据被篡改。

import (
	"golang.org/x/crypto/poly1305"
)

// ================== HMAC ==================

// computeHMAC 计算 HMAC 值
func computeHMAC(hashFunc func() hash.Hash, key, message []byte) string {
	mac := hmac.New(hashFunc, key)
	mac.Write(message)
	return hex.EncodeToString(mac.Sum(nil))
}

// verifyHMAC 验证 HMAC 值
func verifyHMAC(hashFunc func() hash.Hash, key, message []byte, expectedMAC string) bool {
	actualMAC := computeHMAC(hashFunc, key, message)
	return hmac.Equal([]byte(actualMAC), []byte(expectedMAC))
}

// ================== UMAC (使用 Poly1305 实现) ==================

// computeUMAC 计算 UMAC (使用 Poly1305 作为示例实现)
func computeUMAC(key, message []byte) (string, error) {
	if len(key) != 32 {
		return "", fmt.Errorf("UMAC key must be 32 bytes long")
	}

	var keyArray [32]byte
	copy(keyArray[:], key)

	var mac [16]byte
	poly1305.Sum(&mac, message, &keyArray)
	return hex.EncodeToString(mac[:]), nil
}

// verifyUMAC 验证 UMAC
func verifyUMAC(key, message []byte, expectedMAC string) (bool, error) {
	computedMAC, err := computeUMAC(key, message)
	if err != nil {
		return false, err
	}
	return computedMAC == expectedMAC, nil
}

五、应用场景与实践

  1. 网络通信安全:在互联网通信中,加密技术用于保护数据的机密性和完整性。例如,HTTPS 协议使用 TLS/SSL 协议进行加密通信,确保用户与网站之间的数据传输安全。TLS/SSL 协议结合了非对称加密、对称加密和哈希函数,提供了端到端的加密通信。HTTPS 通信简化流程:

    • 客户端发起 SSL 握手请求
    • 服务端返回 RSA/ECC 公钥
    • 客户端生成临时会话密钥(如 AES-256),用公钥加密后传输
    • 双方使用对称密钥加密通信数据

    在这里插入图片描述

  2. 数据存储安全:在数据存储方面,加密技术用于保护敏感数据,如密码、个人身份信息等。例如,许多操作系统和文件系统提供了加密功能,允许用户加密文件和文件夹,防止未授权访问。此外,数据库加密也是保护敏感数据的重要手段,它可以防止未经授权的用户访问数据库中的敏感信息。

  3. 数字签名与身份验证:数字签名是验证消息来源和完整性的有效方法。在电子邮件和软件分发中,数字签名被广泛使用,以确保消息或软件的来源真实可靠。例如,PGPPretty Good Privacy)是一个用于加密和签名电子邮件的软件,它使用 RSADSA 算法进行数字签名,确保邮件的完整性和真实性;并用 AES 对邮件正文进行加密。

  4. 密码存储与验证:在密码存储方面,加密技术用于保护用户密码的安全。传统的做法是将密码存储为明文,这存在严重的安全隐患。现代系统通常使用哈希函数和盐值(salt)来存储密码,确保即使数据库被泄露,攻击者也无法直接获取用户的明文密码。例如,bcrypt 是一种密码哈希算法,它使用慢哈希函数和盐值来保护密码,防止暴力破解和彩虹表攻击(盐(Salt)在密码学中,是指通过在密码任意固定位置插入特定的字符串,让哈希后的结果和使用原始密码的哈希结果不相符,这种过程称之为 “加盐”)。

  5. 微信《电商类小程序结算周期变更通知》回调报文案例:

    • 微信支付平台公钥验签(RSA):https://pay.weixin.qq.com/doc/v3/merchant/4013053420

      {
          "id": "0ce9eec0-be84-53cd-b0b8-0cadcae96e20",
          "create_time": "2025-05-12T16:15:10+08:00",
          "resource_type": "encrypt-resource",
          "event_type": "MERCHANT_NOTIFY.NOTIFY",
          "summary": "订阅消息",
          "resource": {
              "original_type": "merchant_notify",
              "algorithm": "AEAD_AES_256_GCM",
              "ciphertext": "wUMcIAkDIq4jiuS/5jTrtFfdomvbYIX7R8gfF1dgAJBi8htAYsjBm/I5vRaJ80Y+cEBn9/upYFA8LPatkY/uxEuOL/HrSyFo4wvCSH63RFMqUnpbRYki7NiStJsTyzRthkaK2zoyeWH+3xcxVjm/c/05yobLNA1C3Vh41g4CdDBx+eHEOAmBpa8SV9NHcbNzTSOvigOAOHlpFMu6V0NWPTgpQcV7oVM7lv76YWZfujmXKuV/y/lddcnX3irOePywaMjFtbb83q4NcmF1Wu7YIyyy0utiqcACgj+OdekGDqW02skpnLyeKZhJ0u5ptQNPMq6mewUwccJ8KN5eOfwTW9hzlQNB2iDunTaduZcIESq/FRupLRIt+ypTY9QzZqMMap8P2ELEjuMJfBz50tij7KwyxsCUcjY7//EVqRRsb2bnBsXw6jPQNbYZN8oIC03CzUiIfzolJBmDZy++gOpWi3rwxqm/",
              "associated_data": "merchant_notify",
              "nonce": "qfFLtAsgTxyd"
          }
      }
      
      // 读取请求体内容
      bytes, err := io.ReadAll(ctx.Request.Body)
      if err != nil {
          doFailed(ctx, "读取请求体内容失败", err, "")
          return
      }
      defer ctx.Request.Body.Close()
      
      global.ZapLogger.Info("wxmp: request body content", zap.String("reqBody", string(bytes)))
      
      // 签名验证,详见:https://pay.weixin.qq.com/doc/v3/merchant/4013053420
      validHeaderCount := 3
      headers := ctx.Request.Header
      for key, values := range headers {
          for _, value := range values {
              global.ZapLogger.Info("wxmp: callback header", zap.String("key", key), zap.String("val", value))
          }
          if key == constants.HeaderWechatPayTimestamp ||
              key == constants.HeaderWechatPayNonce ||
              key == constants.HeaderWechatPaySignature {
              validHeaderCount--
          }
      }
      if validHeaderCount > 0 {
          doFailed(ctx, "请求头缺失必要验签字段", fmt.Errorf("Wechatpay-Timestamp,Wechatpay-Signature,Wechatpay-Nonce needed"), "")
          return
      }
      needSignStr := fmt.Sprintf("%s\n%s\n%s\n",
          headers[constants.HeaderWechatPayTimestamp][0],
          headers[constants.HeaderWechatPayNonce][0],
          string(bytes),
      )
      err = cipher.VerifyWechatPaySignature(needSignStr, headers[constants.HeaderWechatPaySignature][0], global.AppCfg.WXMP.VerifyPublicKeyFilePath)
      if err != nil {
          doFailed(ctx, "微信订阅消息验签失败", err, "")
          return
      }
      
      
      
      // VerifyWechatPaySignature 验证微信支付签名
      // needSignStr: 需要验签的字符串
      // signature: Base64 编码的签名
      // publicKeyPath: 微信支付平台公钥文件路径
      func VerifyWechatPaySignature(needSignStr, signature, publicKeyPath string) (err error) {
      	// 1. 加载公钥
      	if global.WechatRSAPublicKey == nil {
      		global.WechatRSAPublicKey, err = loadPublicKeyFromCert(publicKeyPath)
      		if err != nil {
      			return
      		}
      	}
      
      	// 2. Base64 解码签名
      	decodedSignature, err := base64.StdEncoding.DecodeString(signature)
      	if err != nil {
      		return
      	}
      
      	// 3. 计算 needSignStr 的 SHA-256 哈希
      	hashed := sha256.Sum256([]byte(needSignStr))
      
      	// 4. 签名验证
      	err = rsa.VerifyPKCS1v15(global.WechatRSAPublicKey, crypto.SHA256, hashed[:], decodedSignature)
      	if err != nil {
      		return
      	}
      
      	return
      }
      
    • 使用 APIv3 密钥解密报文(AES-256-GCM):https://pay.weixin.qq.com/doc/v3/merchant/4012071382

      // 解密前
      {
          "original_type": "merchant_notify",
          "algorithm": "AEAD_AES_256_GCM",
          "ciphertext": "wUMcIAkDIq4jiuS/5jTrtFfdomvbYIX7R8gfF1dgAJBi8htAYsjBm/I5vRaJ80Y+cEBn9/upYFA8LPatkY/uxEuOL/HrSyFo4wvCSH63RFMqUnpbRYki7NiStJsTyzRthkaK2zoyeWH+3xcxVjm/c/05yobLNA1C3Vh41g4CdDBx+eHEOAmBpa8SV9NHcbNzTSOvigOAOHlpFMu6V0NWPTgpQcV7oVM7lv76YWZfujmXKuV/y/lddcnX3irOePywaMjFtbb83q4NcmF1Wu7YIyyy0utiqcACgj+OdekGDqW02skpnLyeKZhJ0u5ptQNPMq6mewUwccJ8KN5eOfwTW9hzlQNB2iDunTaduZcIESq/FRupLRIt+ypTY9QzZqMMap8P2ELEjuMJfBz50tij7KwyxsCUcjY7//EVqRRsb2bnBsXw6jPQNbYZN8oIC03CzUiIfzolJBmDZy++gOpWi3rwxqm/",
          "associated_data": "merchant_notify",
          "nonce": "qfFLtAsgTxyd"
      }
      
      // 解密后
      {
          "message_content": {
              "merchant_code": "781314402",
              "merchant_company_name": "陕西国钢有限公司",
              "business_time": "2020-02-19T18:21:31+08:00",
              "business_code": "wx31f2346bffb82bdf",
              "business_state": "ADJUSTED"
          },
          "topic_name": {
              "topic_english_name": "SettleCycleByAppid",
              "topic_chinese_name": "电商类小程序结算周期变更通知"
          }
      }
      
      // Decrypt 使用 AES-256-GCM 算法解密数据,加密内容先用 base64 解码
      func Decrypt(ciphertext, associatedData, key, nonce string) (plaintext string, err error) {
      	// AES-256 需要一个 32 字节长度的密钥
      	keyBytes := []byte(key)
      	if len(keyBytes) != 32 {
      		err = errors.New("key length must be 32 bytes")
      		return
      	}
      
      	block, err := aes.NewCipher(keyBytes)
      	if err != nil {
      		return
      	}
      
      	// 创建 GCM 实例
      	aesGCM, err := cipher.NewGCM(block)
      	if err != nil {
      		return
      	}
      
      	// 解码密文
      	ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertext)
      	if err != nil {
      		return
      	}
      
      	// 解密
      	plaintextBytes, err := aesGCM.Open(nil, []byte(nonce), ciphertextBytes, []byte(associatedData))
      	if err != nil {
      		return
      	}
      
      	return string(plaintextBytes), nil
      }
      

六、算法选择指南

  1. 算法分类与核心用途:

    算法分类特点典型应用推荐算法
    对称加密加解密使用相同密钥,速度快大数据量加密、数据库加密、实时通信AES (128/192/256位):全球标准,硬件加速支持
    SM4:中国商用密码标准,与 AES 相当
    ChaCha20:移动设备首选,比 AES 更抗侧信道攻击
    非对称加密公私钥分离,速度慢但无需密钥交换密钥协商、数字签名、身份认证RSA (2048位以上):兼容性最广,适合加密小数据
    ECC (P-256/P-384):同等安全下密钥更短,移动端首选
    SM2:中国商用标准,基于 ECC 改进
    哈希算法单向不可逆,固定长度输出数据完整性校验、密码存储、数字指纹SHA-256/512:通用安全哈希
    SM3:中国商用标准,安全性等同 SHA-256
    Argon2 (密码存储专用):抗 GPU/ASIC 破解
    消息认证码(MAC)带密钥的哈希,验证来源和完整性API请求验证、金融交易防篡改HMAC-SHA256:通用标准

    Poly1305 (配合ChaCha20):高性能场景
    GMAC (GCM模式专用):加密同时认证
  2. 选择决策树:

    是否需要...
    ├─ 加密大数据? → 对称加密(AES/SM4)
    ├─ 安全交换密钥? → 非对称加密(ECC/RSA)
    ├─ 验证数据完整性? → 哈希(SHA-256/SM3)
    └─ 验证消息来源? → MAC(HMAC/Poly1305)
    
  3. 安全等级推荐:

    安全需求推荐算法组合
    基础安全AES-128 + SHA-256
    商业级AES-256-GCM + ECC-P256 + HMAC
    金融/政府SM4-CBC + SM2 + SM3 + HMAC-SM3
    超高安全ChaCha20-Poly1305 + Ed448
  4. 国密算法应用场景:

    • SM4:替代 AES,所有电子政务系统强制要求
    • SM2:替代 RSA/ECC,数字证书、VPN 身份认证
    • SM3:替代 SHA-256,区块链、数字签名

七、安全性分析

  1. 密钥管理的重要性:密钥管理是加密系统中至关重要的一环。如果密钥被泄露或丢失,加密数据的安全性将受到严重威胁。因此,密钥管理需要遵循一系列最佳实践,包括密钥生成、存储、分发和销毁等环节。例如,密钥应该使用加密随机数生成器生成,存储时应该加密,分发时应该通过安全信道,销毁时应该彻底删除,防止恢复。
  2. 算法强度与密钥长度:加密算法的安全性与其强度和密钥长度密切相关。一般来说,密钥长度越长,破解难度越大。例如,AES 使用 128 位密钥被认为是安全的,但对于高安全要求的场景,可能需要使用 192 位或 256 位密钥。同样,RSA 的密钥长度也应该足够长,目前推荐使用 2048 位或更长的密钥。
  3. 侧信道攻击与物理安全:除了传统的密码分析攻击外,侧信道攻击也是加密系统面临的重要威胁。侧信道攻击通过分析加密设备的物理特性,如功耗、电磁辐射等,推断出密钥信息。因此,加密系统需要考虑物理安全,防止侧信道攻击。例如,硬件加密设备应该设计为抗侧信道攻击,软件加密也应该避免在内存中明文存储密钥。

八、未来发展趋势

  1. 后量子加密技术:随着量子计算的发展,传统的加密算法可能面临被破解的风险。量子计算机可以高效地解决大整数分解和离散对数问题,这将使 RSAECC 等加密算法失效。因此,研究后量子加密技术成为当前的重要课题。后量子加密技术基于不同的数学难题,如格基密码、多变量密码、哈希基密码等,这些算法在量子计算下仍然保持安全性。例如,NIST(美国国家标准与技术研究院)已经启动了后量子密码标准的评选工作,预计将在未来几年内确定最终标准。
  2. 零知识证明与隐私保护:零知识证明是一种允许一方证明自己拥有某个信息,而不必透露该信息本身的技术。它在隐私保护方面具有重要应用,例如在区块链和匿名通信中。随着对隐私保护需求的增加,零知识证明技术将得到更广泛的应用和发展。例如,zk-SNARKs(零知识简洁非交互式知识论证)已经在 Zcash 等加密货币中使用,允许用户在不泄露交易细节的情况下验证交易的有效性。
  3. 区块链与加密货币:区块链和加密货币的发展也对加密技术提出了新的要求和挑战。区块链使用加密哈希和数字签名来确保交易的完整性和真实性,而加密货币如比特币和以太坊则使用密码学来保护交易和账户的安全。未来,随着区块链和加密货币的进一步发展,新的加密技术也将不断涌现,以满足这些系统的需求。例如,同态加密允许在加密数据上进行计算,这在区块链智能合约中具有重要应用。

九、结论

加密技术是保护数字世界安全的核心工具,随着技术的发展和威胁的演变,加密算法也在不断进步。从对称加密到非对称加密,从传统哈希函数到后量子加密,加密技术的发展历程体现了人类在保护信息安全方面的不懈努力。在未来的数字化社会中,加密技术将继续发挥关键作用,为我们的数据和通信提供安全保障。

十、附录

国密即国家密码局认定的国产密码算法。主要有 SM1SM2SM3SM4

  1. SM1 为对称加密。其加密强度与 AES 相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
  2. SM2 为非对称加密,基于 ECC。该算法已公开。由于该算法基于 ECC,故其签名速度与秘钥生成速度都快于 RSAECC256 位安全强度比 RSA2048 位高,但运算速度快于 RSA
  3. SM3 为哈希算法。可以用 MD5 作为对比理解。该算法已公开。校验结果为 256 位。
  4. SM4 为对称加密,密钥长度和分组长度均为 128 位,是无线局域网标准的分组数据算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

春天熊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值