C# 密码学高级教程(四)
九、C# 和 .NET
在这一章中,我们将介绍一些可以在中使用的最重要的加密库 .NET 和 C# 应用。选择一个加密库,尤其是开源的加密库,与 .NET 框架本身。你需要确定你在做什么,并且知道你在使用什么样的数据。如果开源项目中存在可被攻击者利用的漏洞,那么在安全方面依赖开源项目可能会导致重大的安全事故。
在接下来的章节中,我们将介绍这些库:NSec [1 ]、弹力城堡 [2 ]、地狱 [3 ]和 SecureBlackbox [4 。
毫微秒或纳秒(nanosecond 或 nanoseconds)
NSec [1 ]是最现代、最易于使用的加密库之一 .NET 核心。该库基于 lib 钠 [5 ]。
NSec 的一些特点如下:
-
现代方法。libna 提供了一小组加密算法和原语。与其他库相比,NSec 和 lib 钠的优点是支持 X25519、Ed25519 和 ChaCha-Poly1305 等特性。NSec 内的性能和功能实现方式基于现代。基于类型
Span<T>和ReadOnlySpan<T>.开发的. NET API -
极其好用。这是非常有用和易于使用的。NSec 的优雅和可靠性意味着它易于实施。它提供了对类型数据模型的支持,这种模型是基于专用类而不是空字节数组来设计的,考虑到了键和共享秘密。这有助于开发人员避免在错误的算法中使用密钥。
-
安全。NSec 的任务是使密码原语尽可能简单。
-
快。NSec 和 libna 在加密过程中速度非常快。堆没有分配内存。NSec 旨在避免任何类型的内存分配或无用的副本。
-
敏捷。NSec 中实现的大多数算法都是从一小组基类中派生出来的。目的是提供一种针对算法接口而不是特定算法编写代码的高效方法。
在下面的例子中,您将看到 NSec 是如何工作的,以及它是多么容易使用。NSec 成功地使用了 C# 8.0 的一些特性,它们非常容易识别和理解。
清单 9-1 展示了如何使用 Ed25519 签名算法和签名消息。图 9-1 显示了输出。
图 9-1
NSec 输出
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NSec.Cryptography;
namespace NSecLibrary
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("NSec Library");
//** select the Ed25519 signature algorithm
var algorithm = SignatureAlgorithm.Ed25519;
//** create a new key pair
var key = Key.Create(algorithm);
//** generate some data to be signed
var data = Encoding.UTF8.GetBytes("Use the Force, Luke!");
//** sign the data using the private key
var signature = algorithm.Sign(key, data);
//** verify the data using the signature and the public key
if (algorithm.Verify(key.PublicKey, data, signature))
{
Console.WriteLine("The message ");
for (int i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString() + " ");
}
Console.WriteLine("\n has been verified with success.");
}
else
{
Console.WriteLine("The message: {0} has not been verified.", data.ToString());
}
}
}
}
Listing 9–1Ed25519 Signature
NSec 安装
可以使用 NuGet 包 [6 ]找到并安装 NSec,它包含安装过程所需的所有细节(见图 9-2 )。
图 9-2
NSec。加密 NuGet 包
还可以通过以下不同方式将 NSec 添加到项目中:
-
使用点网命令行界面:
-
使用 Visual Studio :
$ dotnet add package NSec.Cryptography –-version XX.X.X
- 使用 *中的引用。csproj 文件:
PM> Install-Package NSec.Cryptography -Version XX.X.X
<PackageReference Include="NSec.Cryptography" Version="XX.X.X"/>
大型充气城堡型玩具
充气城堡是最重要和最著名的图书馆之一。它包含加密算法和协议的 C# 实现。
它有很多有用的特性。最重要的特性列表如下所示:
-
“支持解析和生成 PKCS-12 文件” 7 。
-
"X.509 :支持 V1 和 V3 证书(生成和解析)。此外,V2 CRL 和证书基于属性“ 7 ”。
-
“性能支持的 PBE 算法”[7。
-
“签名者支持的签名算法”[7。
-
“对称密钥算法 : AES,Blowfish,Camellia,CAST5,CAST6,ChaCha,DES,DESede,GOST28147,HC-128,HC-256,IDEA,ISAAC,Noekeon,RC2,RC4,RC5-32,RC5-64,RC6,Rijndael,Salsa20,SEED,Serpent,Skipjack,TEA/XTEA,Threefish,Tnepres,Twofish,VMPC 和 xsalsa 20”7
-
“对称密钥模式 : CBC、CFB、CTS、GOFB、OFB、OpenPGPCFB、SIC(或 CTR)”[7。
-
“对称密钥填充:PKCS ISO10126d2、ISO7816d4-5/7、TBC、X.923、零字节” 7 。
-
“非对称密钥算法 : ElGamal,DSA,ECDSA,NaccacheStern,RSA(带盲)” [7 。
-
“非对称密钥填充/编码s:OAEP、PKCS 和 ISO9796d1-1”7。
-
“AEAD 分组密码模式 : CCM、EAX、GCM、OCB”7。
-
“摘要 : GOST3411,Keccak,MD2,MD4,MD5,RIPEMD128,RIPEMD160,RIPEMD256,RIPEMD320,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512,SHA3,老虎,漩涡” 7 。
-
" XOFs:SHAKE "7。
-
“签名人机制 : DSA,ECDSA,ECGOST3410,ECNR,GOST3410,ISO9796d2,PSS,RSA,x 9.31-1998”7。
-
“密钥协议:迪菲-海尔曼,EC-DH,EC-MQV,J-帕克,SRP-6a”7。
-
MAC:cbcbl lock cipher、CFBBlockCipher、CMAC、GMAC、GOST28147、HMac、ISO9797 Alg。3、聚 1305、SipHash、SkeinMac、vmpcm AC "[7。
-
“PBE 发电机 : PKCS-12,PKCS-5——方案一和方案二” 7 。
-
open PGP(RFC 4880)[7]t1。
-
“加密消息语法(CMS,RFC 3852),包括流式 API”7。
-
“在线证书状态协议(OCSP,RFC 2560)”[7。
-
“时间戳协议(TSP,RFC 3161)”[7。
-
“TLS/DTLS 客户端/服务器版本 1.2,支持最常用的密码套件和扩展,以及许多不常用的密码套件和扩展。可用的非阻塞 API "7。
-
椭圆曲线密码。
充气城堡示例
清单 9-2 展示了一个使用 Bouncy Castle 生成密钥的例子。在图 9-3 中,您可以看到密钥大小设置为 256 的输出。
图 9-3
使用 BouncyCastle 生成加密密钥
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace BouncyCastleLibrary
{
class Program
{
public static string Xvalue;
public static string Yvalue;
public static int Dvalue;
static void Main(string[] args)
{
Console.WriteLine("Using BouncyCastle Library to show how we can generate cryptography keys (private and public).\n");
Console.WriteLine("Please, choose the size of the keys (128 or 256)");
int key_size = Convert.ToInt32(Console.ReadLine());
if (key_size == 128)
KeyGeneration(128);
else if (key_size == 256)
KeyGeneration(256);
}
public static AsymmetricCipherKeyPair GenerateKeys(int keySize)
{
//** choosing ECDSA for key generation
var key_generation = new ECKeyPairGenerator("ECDSA");
//** for creating randomly values
var randomly_secure_value = new SecureRandom();
//** generating the parameters based on the random value and size of the key
var key_generation_parameters = new KeyGenerationParameters(randomly_secure_value, keySize);
//** proceed with the initialization of the generation algorithm with parameters
key_generation.Init(key_generation_parameters);
//** the key pair generation
return key_generation.GenerateKeyPair();
}
public static void KeyGeneration(int key_size)
{
//** generating process
var key_pair = GenerateKeys(key_size);
TextWriter text_writer = new StringWriter();
PemWriter pem_writer = new PemWriter(text_writer);
pem_writer.WriteObject(key_pair.Private);
pem_writer.Writer.Flush();
string privateKey = text_writer.ToString();
Console.WriteLine("The private key is: {0}", privateKey);
ECPrivateKeyParameters privateKeyParam = (ECPrivateKeyParameters)key_pair.Private;
Console.WriteLine("D value is: {0}", privateKeyParam.D.ToString());
text_writer = new StringWriter();
pem_writer = new PemWriter(text_writer);
pem_writer.WriteObject(key_pair.Public);
pem_writer.Writer.Flush();
ECPublicKeyParameters publicKeyParam = (ECPublicKeyParameters)key_pair.Public;
string publickey = text_writer.ToString();
Console.WriteLine("The public key is: {0}", publickey);
Console.ReadKey();
Xvalue = publicKeyParam.Q.XCoord.ToBigInteger().ToString();
Yvalue = publicKeyParam.Q.YCoord.ToBigInteger().ToString();
}
}
}
Listing 9-2AES – Encryption with CBC Mode and PKCS5/7 Padding
接下来的三个例子(见清单 9-3 、清单 9-4 和清单 9-5 )展示了如何处理密钥协商和交换算法。
如果您正在处理一个基本协议(参见清单 9-3 ),该协议使用了一个具有约定值的余因子,下面的例子应该很能说明问题。
public byte[] AgreementOnAgreedValue
(AsymmetricECPrivateKey privateKey,
AsymmetricECPublicKey otherEncKey)
{
IAgreementCalculatorService createService =
CryptoServicesRegistrar.CreateService(privateKey);
IAgreementCalculator<FipsEC.AgreementParameters>
contract_agreement =
createService.CreateAgreementCalculator(FipsEC.Cdh);
return contract_agreement.Calculate(otherEncKey);
}
Listing 9-3Basic Agreement with an Agreed Value
在清单 9-4 中,您可以看到如何使用 SHA256 函数和 PRF(伪随机函数)函数来计算商定的值。
public byte[] AgreementOnAgreedValueWithPrf
(AsymmetricECPrivateKey privateKey,
AsymmetricECPublicKey otherEncKey,
byte[] paddingSalt)
{
IAgreementCalculatorService createService =
CryptoServicesRegistrar.CreateService(privateKey);
IAgreementCalculator<FipsEC.AgreementParameters>
contract_agreement = dhFact.CreateAgreementCalculator
(FipsEC.Cdh.WithKeyMaterialGenerator
(new FipsPrfKmg
(FipsPrfAlgorithm.Sha256HMac,
paddingSalt));
return contract_agreement.Calculate(otherEncKey);
}
Listing 9-4Agreement Using PRF
清单 9-5 显示了与 X9.63 KDF(密钥派生函数)的另一种协议。
public byte[] AgreementWithCofactorAndKdf
(AsymmetricECPrivateKey privateKey,
AsymmetricECPublicKey otherEncKey,
byte[] paddingSalt)
{
IAgreementCalculatorService createService =
CryptoServicesRegistrar.CreateService(privateKey);
IAgreementCalculator<FipsEC.AgreementParameters>
contract_agreement =
dhFact.CreateAgreementCalculator
(FipsEC.Cdh.WithKeyMaterialGenerator
(new FipsKdfKmg(FipsKdf.X963,
paddingSalt, 32));
return agreement.Calculate(otherEncKey);
}
Listing 9-5Working with an Agreement Based on X9.63 KDF
充气城堡装置
充气城堡可以使用 NuGet 包 [8 ]找到并安装,它包含了安装过程所需的所有细节(见图 9-4 )。
图 9-4
充气城堡 NuGet 套餐
弹力城堡也可以通过以下方式添加到项目中:
-
使用点网命令行界面:
-
使用 Visual Studio :
$ dotnet add package BouncyCastle –-version XX.X.X
- 使用 *中的引用。csproj 文件:
PM> Install-Package BouncyCastle -Version XX.X.X
<PackageReference Include="BouncyCastle" Version="XX.X.X"/>
地狱
Inferno 是另一个有趣的加密库 .NET 使用 C# 开发。它在编写代码时提供了一种独特的优雅,在处理代码时获得的性能非常有前途。
以下列表代表了 Inferno 的特性 [9 :
-
"[random]: CryptoRandom( .NET Random done right)" [9
-
"[密码]:仅 AES-256(快速、恒定时间、抗旁路 AES-NI)" [9 ]
-
"[高级]: AEAD (AES-CTR-HMAC)。流式 AEAD (EtM 转换)" [9
-
"[ciphers-misc]: AES-CTR 实现(密码转换)" [9 ]
-
"[ciphers-misc]:AEAD(AES-CBC-HMAC)"[9]
-
"[哈希]: SHA2 哈希工厂(256,384,512)。推荐 SHA-384(默认)" [9 ]
-
"[hash]: SHA1 哈希工厂(主要用于遗留集成)" [9 ]
-
“[mac]: HMAC2( .NET HMAC 做得对) [9
-
"[mac]: HMAC-SHA1,HMAC-SHA2 工厂"9
-
“[kdf]: HKDF,PBKDF2,SP800_108_Ctr。支持任何 HMAC 工厂" 9
-
"[助手]" [9 ]
-
“常量时间字节和字符串比较”9
-
“安全的 UTF8”9
-
“快速 64 位字节数组异或”9
-
地狱的例子
以下示例展示了如何使用该库的案例研究。在清单 9-6 中,您可以看到处理加密、解密和认证的函数的基本声明。注意函数的灵活性和提示性声明。
//** The namespace that has to be used when working with
//** Inferno is: SecurityDrive.Inferno
//** If SecurityDrive.Inferno is not visible it means that is
//** not properly installed and it is necessary to check the
//** section "Inferno Installation"
public static class BasicOperations
{
public static byte[] Encrypt(byte[] master_crypto_key,
ArraySegment<byte> clearText,
ArraySegment<byte>? saltPadding = null);
public static byte[] Decrypt(byte[] master_crypto_key,
ArraySegment<byte> cryptotext,
ArraySegment<byte>? saltPadding = null);
public static bool Authenticate(byte[] master_crypto_key,
ArraySegment<byte> cryptotext,
ArraySegment<byte>? saltPadding = null);
}
Listing 9-6Encryption, Decryption, and Authentication Functions
使用散列函数(见清单 9-7 )非常有趣和简单。一旦你到达流程和应用的末尾,调用dispose是非常重要的。
public static Func<SHA384> HashFactory
Listing 9-7Working with Hash
清单 9-8 展示了如何使用 HMAC。
var dataForHmac = Utils.SafeUTF8.GetBytes("Welcome To Apress!");
//** this is for HMACSHA384
using (var theHmac = SuiteB.HmacFactory())
{
theHmac.Key = new byte[] { 6, 5, 4, 3, 2 };
theHmac.ComputeHash(dataForHmac).ToBase16().Dump();
}
Listing 9-8Using HMAC
清单 9-9 显示了 DSA(数字签名算法)的使用情况。图 9-5 显示了输出。
图 9-5
输出
using SecurityDriven.Inferno.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace InfernoLibrary
{
class Program
{
static void Main(string[] args)
{
//** generate the DSA keys
CngKey thePrivateKey = CngKeyExtensions.CreateNewDsaKey();
//** generate the cryptographic keys
//** that will be used with DSA
byte[] dsa_private_key_blob = thePrivateKey.GetPrivateBlob();
//** convert and store private key as bytes
byte[] dsa_public_key_blob = thePrivateKey.GetPublicBlob();
//** convert and store public key as bytes
CngKey dsa_public_key = dsa_public_key_blob.ToPublicKeyFromBlob();
//** some data (sample)
byte[] data_sample = Guid.NewGuid().ToByteArray();
byte[] theSignature = null;
//** using the private key, generate the
//** DSA signature and store it properly
using (var ecdsaAlgorithm = new ECDsaCng(thePrivateKey) { HashAlgorithm = CngAlgorithm.Sha384 })
{
theSignature = ecdsaAlgorithm.SignData(data_sample);
}
//** play with the data
data_sample[5] ^= 1;
Console.WriteLine("Private key is: {0}", BitConverter.ToString(dsa_private_key_blob));
Console.WriteLine("\nPublic key is: {0}", BitConverter.ToString(dsa_public_key_blob));
Console.WriteLine("\nSample data: {0}", BitConverter.ToString(data_sample));
Console.WriteLine("\nThe signature is: {0}", BitConverter.ToString(theSignature));
//** using the public key, verify the DSA signature
using (var ecdsaAlgorithm = new ECDsaCng(dsa_public_key){ HashAlgorithm = CngAlgorithm.Sha384})
{
if (ecdsaAlgorithm.VerifyData(data_sample, theSignature))
{
Console.WriteLine("\nOups! Something went wrong. Signature was unable to be verified properly.");
}
else
{
Console.WriteLine("\nThe signature has been verified with success.");
}
Console.ReadKey();
}
}
}
}
Listing 9-9Dealing with a DSA
地狱装置
使用 NuGet 包 [10 ]可以找到并安装 Inferno,它包含了安装过程所需的所有细节(参见图 9-6 )。
图 9-6
Inferno NuGet 包
Inferno 也可以通过以下方式添加到项目中:
-
使用点网命令行界面:
-
使用 Visual Studio :
$ dotnet add package Inferno –-version XX.X.X
- 使用 *中的引用。csproj 文件:
PM> Install-Package Inferno -Version XX.X.X
<PackageReference Include="Inferno" Version="XX.X.X"/>
安全黑盒
SecureBlackbox 是处理数字安全和网络安全的最全面的工具和类集之一。
开发安全解决方案的方式与 NSec 或 Inferno 相同。方法和功能类似于 NSec 和 Inferno 的方法和功能。差异非常小,并且是特定于缓冲区数组的分配。
图书馆不是免费的。要运行清单 9-10 中的示例,您需要一个许可证。一旦运行该应用,将显示来自图 9-7 的消息。
图 9-7
运行该示例所需的许可证
出于测试目的,对于清单 9-10 中的示例,可以联系库的所有者,他们会向您提供一个临时许可证密钥。
一旦收到许可证(通常是一个文本文件,如LicenseKey.txt),就可以调用两个函数,并将许可证作为它们的关键参数。这两个功能是void SetLicenseKey(ByteArray key)和void SetLicenseKey(string key).
如果您同时需要更多的密钥许可,只需使用不同的文件名多次调用该函数。每个许可证应该有不同的名称。
using SBSymmetricCrypto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SecureBlackBoxLibrary
{
class Program
{
static void Main(string[] args)
{
var key = "b14ca5898a4e4133bbce2ea2315a1916";
byte[] encryptionKeyBuffer;
byte[] initializationBuffer = new byte[16];
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = initializationBuffer;
encryptionKeyBuffer = aes.Key;
initializationBuffer = aes.IV;
}
//** create a crypto factory instances
//** used for symmetric encryption
TElSymmetricCryptoFactory symmetric_factory_container = new TElSymmetricCryptoFactory();
//** use the factory container to
//** declare an appropriate algorithm
TElSymmetricCrypto symmetric_encryption = symmetric_factory_container.CreateInstance (SBConstants.Unit.SB_ALGORITHM_CNT_AES256, TSBSymmetricCryptoMode.cmDefault);
//** declare a key and assign the proper
//** value for the secret key and the initialization vector
TElSymmetricKeyMaterial km = new TElSymmetricKeyMaterial(null);
km.Key = encryptionKeyBuffer;
km.IV = initializationBuffer;
//** assign the key container to the cryptographic
//** object using the property KeyMaterial
symmetric_encryption.KeyMaterial = km;
//** proceed further with the encryption
byte[] input_buffer = Encoding.UTF8.GetBytes("Welcome to Apress!");
//** declare the output_buffer and output_size and initialize //** them with 0\. In this way we will point out that the first //** invoked is getting the call.
byte[] output_buffer = null;
int output_size = 0;
//** Finding out about the output
//** length - this may be approximate
symmetric_encryption.Encrypt(input_buffer, 0, input_buffer.Length, ref output_buffer, 0, ref output_size);
//** create an allocation as an array for the output data
output_buffer = new byte[output_size];
//** do the encryption
symmetric_encryption.Encrypt(input_buffer, 0, input_buffer.Length, ref output_buffer, 0, ref output_size);
//**copy the data that has been encrypted to a dedicate buffer
output_buffer = SBUtils.Unit.CloneArray(output_buffer, 0, output_size);
//** before continue with the encryption
//** invoke InitializeEncryption method
//** within the cryptographic object
symmetric_encryption.InitializeEncryption();
//** as much as it is required, pass the data as necessary
//** using invokations of EncryptUpdate()
symmetric_encryption.EncryptUpdate(input_buffer, 0, input_buffer.Length, ref output_buffer, 0,ref output_size);
output_buffer = SBUtils.Unit.CloneArray(output_buffer, 0, output_size);
//** Once we reach at the end of EncryptUpdate(),
//** we need to endup the encryption
//** by invoking FinalizeEncryption() method
symmetric_encryption.FinalizeEncryption(ref output_buffer, 0, ref output_size);
output_buffer = SBUtils.Unit.CloneArray(output_buffer, 0, output_size);
Console.WriteLine("The encryption key is: {0}", key);
Console.WriteLine("\nThe buffer for encryption key is: {0}", BitConverter.ToString(encryptionKeyBuffer));
Console.WriteLine("\nThe initialization buffer is: {0}", BitConverter.ToString(initializationBuffer));
Console.WriteLine("\nThe encryption is: {0}", symmetric_encryption.ToString());
Console.ReadKey();
}
}
}
Listing 9-10Example of Symmetric Encryption with SecureBlackbox
SecureBlackbox 安装
可以使用 NuGet 包 [10 ]找到并安装 SecureBlackbox,它包含安装过程所需的所有细节(参见图 9-8 )。
图 9-8
SecureBlackbox NuGet 包
还可以通过以下方式将 SecureBlackbox 添加到项目中:
-
使用点网命令行界面:
-
使用 Visual Studio :
$ dotnet add package SecureBlackbox –-version XX.X.X
- 使用 *中的引用。csproj 文件:
PM> Install-Package SecureBlackbox -Version XX.X.X
<PackageReference Include=" SecureBlackbox" Version="XX.X.X"/>
结论
在本章中,我们介绍了最重要的加密库(NSec、Bouncy Castle、Inferno 和 SecureBlackbox ),它们可以作为指南、额外的库和工具,用于在专业人员开发的应用中实现数据的机密性、完整性和真实性。用于选择这些库的标准是它们被该领域的其他专业人员认可以及 FIPS 和 NIST 标准。
这些库可以与System.Security.Cryptography名称空间并行使用,提供了更全面的加密原语。
文献学
-
NSec。在线可用:
https://nsec.rocks/. -
充气城堡。在线可用:
https://cryptobook.nakov.com/crypto-libraries-for-developers/c-crypto-libraries. -
SecureBlackbox。在线可用:
https://nugetmusthaves.com/Package/SecureBlackbox. -
libna for . net .在线可用:
https://nugetmusthaves.com/Package/libsodium-net. -
NSec.Cryptography .可在线获得:
www.nuget.org/packages/NSec.Cryptography/20.2.0. -
充气城堡特色。网上有:
www.bouncycastle.org/csharp/index.html。 -
充气城堡 NuGet 套餐。网上有:
www.nuget.org/packages/BouncyCastle/。 -
地狱的特点和项目。网上有:
https://securitydriven.net/inferno/。 -
地狱 NuGet 包。网上有:
www.nuget.org/packages/Inferno/。 -
SecureBlackbox NuGet 包。网上有:
www.nuget.org/packages/SecureBlackbox/。
十、椭圆曲线密码术
椭圆曲线加密(ECC)是一种基于有限域上椭圆曲线的代数结构的公钥加密方法。ECC 可用于密码学应用和原语,如*密钥协议、数字签名、和伪随机发生器。*它们可用于加密等操作,这种操作通过密钥协议与对称加密方案的组合来实现。在基于椭圆曲线(EC)的整数因式分解算法的几次尝试中可以看到一些其他有趣的用法,在密码学中的应用,例如伦斯特拉椭圆曲线因式分解(L-ECC) [1 ]。
微软 .NET 通过对椭圆曲线 Diffie-Hellman (ECDH)算法的下一代加密(CNG)实现,为 ECC 提供了强有力的支持。
对于密码分析使用的扩展功能,很少有开放源代码库可用于 C# 中的 ECC。使用最多的一个是 Bouncy Castle,支持 P-128 曲线,并计划将支持扩展到 P-256 曲线。
在这一章中,我们将提供两个例子。第一个例子(清单 10-1 )使用了微软的ECDiffieHellmanCng类。第二个例子(清单 10-2 )使用 Bouncy Castle 库来说明这些功能。
ecdiffiehellmancng class
清单 10-1 展示了如何使用ECDiffieHellmanCng类来设置密钥交换。我们将解释密钥如何进一步用于通过公共信道发送并由接收者解密的消息加密(见图 10-1 )。
图 10-1
使用 ECDiffieHellmanCng 的加密输出
下面,我们来仔细看看实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;
namespace ECDiffiedHellmanCng
{
class Program
{
//** Alice User
class UserA
{
//** represents the public key of alice
public static byte[] pk_alice;
public static void Main(string[] args)
{
string message_send_by_alice = "Hello Bob,
Welcome to CryptoWorld!";
using (ECDiffieHellmanCng user_alice = new
ECDiffieHellmanCng())
{
user_alice.KeyDerivationFunction =
ECDiffieHellmanKeyDerivationFunction.Hash;
user_alice.HashAlgorithm =
CngAlgorithm.Sha256;
pk_alice =
user_alice.PublicKey.ToByteArray();
//** we send to Bob
UserB user_bob = new UserB();
CngKey k = CngKey.Import(user_bob.pk_bob,
CngKeyBlobFormat.EccPublicBlob);
byte[] alice_key =
user_alice.DeriveKeyMaterial(CngKey
.Import(user_bob.pk_bob,
CngKeyBlobFormat.EccPublicBlob));
byte[] encryptionOfMessage = null;
byte[] initialize_vector = null;
//** sending the message
SendMessage(alice_key,
message_send_by_alice,
out encryptionOfMessage,
out initialize_vector);
Console.WriteLine("\n\nALICE Side");
Console.WriteLine("==========\n");
Console.WriteLine("\tAlice sends: {0}",
message_send_by_alice);
Console.WriteLine("\tAlice public key:{0}",
PrintByteArray(pk_alice).ToString());
Console.WriteLine("\tThe initialization
vector (IV): {0} ",
PrintByteArray(initialize_vector).
ToString());
Console.WriteLine("\tLength of the message: {0}”,
message_send_by_alice.Length.ToString());
//** receiving message
user_bob.ReceivingMessage(encryptionOfMessage,
initialize_vector);
}
}
//** the function will help us
//** to convert a byte to string.
public static StringBuilder PrintByteArray(byte[] bytes)
{
var string_builder = new StringBuilder("new byte[] { ");
foreach (var theByte in bytes)
{
string_builder.Append(theByte + " ");
}
string_builder.Append("}");
return string_builder;
}
private static void SendMessage(byte[] key,
string theSecretMessage,
out byte[] encryption_message,
out byte[] initialize_vector)
{
//** we will use AES cryptography
//** algorithm for encryption
using (Aes aes_crypto_alg = new
AesCryptoServiceProvider())
{
aes_crypto_alg.Key = key;
initialize_vector = aes_crypto_alg.IV;
//** we encrypt the message using AES
using (MemoryStream encrypted_text = new
MemoryStream())
using (CryptoStream crypto_stream = new
CryptoStream(encrypted_text,
aes_crypto_alg.CreateEncryptor(),
CryptoStreamMode.Write))
{
byte[] clear_text =
Encoding.UTF8.GetBytes(theSecretMessage);
crypto_stream.Write(clear_text,
0, clear_text.Length);
//** close the stream!
crypto_stream.Close();
encryption_message =
encrypted_text.ToArray();
}
Console.WriteLine("\n\n(Encrypted) Message
sent from Alice -> Bob");
Console.WriteLine("\tSecret message is: {0}", theSecretMessage.ToString());
Console.WriteLine("\tEncryptedMessage is: {0}", PrintByteArray(encryption_message).ToString());
Console.WriteLine("\tInitialize vector is: {0}", PrintByteArray(initialize_vector).ToString());
}
}
}
//** User Bob
public class UserB
{
//** the public key of bon
public byte[] pk_bob;
private byte[] bob_key;
public UserB()
{
using (ECDiffieHellmanCng user_bob = new
ECDiffieHellmanCng())
{
user_bob.KeyDerivationFunction =
ECDiffieHellmanKeyDerivationFunction.Hash;
user_bob.HashAlgorithm =
CngAlgorithm.Sha256;
pk_bob = user_bob.PublicKey.ToByteArray();
bob_key =
user_bob.DeriveKeyMaterial(CngKey.Import
(UserA.pk_alice, CngKeyBlobFormat.EccPublicBlob));
}
}
public void ReceivingMessage(
byte[] message_encrypted,
byte[] initialize_vector)
{
using (Aes aes = new
AesCryptoServiceProvider())
{
aes.Key = bob_key;
aes.IV = initialize_vector;
//** let's decrypt the message
using (MemoryStream plaintext = new
MemoryStream())
{
using (CryptoStream crypto_stream =
new CryptoStream(plaintext,
aes.CreateDecryptor(),
CryptoStreamMode.Write))
{
crypto_stream.Write(
message_encrypted,
0,
message_encrypted.Length);
crypto_stream.Close();
string message = Encoding.UTF8.GetString(plaintext.ToArray());
Console.WriteLine("\n\nBOB Side");
Console.WriteLine("The plaintext message is: {0}", message);
Console.WriteLine("The length of the message received by Bob is : {0}",
message.Length.ToString());
Console.ReadKey();
}
}
}
}
}
}
}
Listing 10-1Implementation of ECDiffieHellmanCng
将 ECC 用于弹力城堡库
Bouncy Castle 库 [2 ]代表了一个可以在密码学中使用的 API 集合。对于这个例子,我们将使用 P-128 曲线支持,我们将为选定的曲线生成关键点,并且我们将在控制台中输出结果。
下面的例子由两个类组成,代表项目主类的Program类和EllipticCurveKeyGenerator类。项目结构的快速概述见图 10-2 。在运行项目之前,请从 Microsoft Visual Studio 或使用 PowerShell 安装 Bouncy 库。在“Bouncy Castle 安装”一节中,有一个关于如何使用 Microsoft Visual Studio 执行安装的指南。
图 10-2
充气城堡项目结构
The Program类(见清单 10-2 )代表项目的主类,包含三个功能:Main、GeneratePKeys()和AsymmetricCipherKeyPair GenerateKeys()。每个功能及其用途的描述如下:
-
Main函数:首先执行的主函数。包含一般的输出消息,并针对两种类型的大小(128 和 256 字节)调用GeneratePKeys()函数。 -
GeneratePKeys(int intSize)函数:该函数根据在Main函数中作为参数发送的大小生成一对密钥。TextWriter类帮助我们按顺序书写字符。它是一个抽象类。PemWriter类代表一个通用类,帮助我们处理 OpenSSL PEM 对象。ECPrivateKeyParameters类用于指定椭圆曲线的私钥参数,与ECPublicKeyParameters类的方式相同。 -
AsymmetricCipherKeyPair GenerateKeys(int keySize)函数:该函数使用 ECDSA 生成密码的密钥。为了生成参数,我们将使用KeyGenerationParameters构造函数类,我们将发送两个参数,随机安全值(secureRandom)和密钥大小(keySize)。使用Init() function,我们将初始化 ECDSA 算法,并使用GenerateKeyPair()函数生成密钥对。
EllipticCurveKeyGenerator类(参见清单 10-3 )覆盖了来自IAsymmetricCipherKeyPairGenerator接口的函数和方法。这个类有两个构造函数,EllipticCurveKeyGenerator()和EllipticCurveKeyGenerator(string choose_algorithm)。注意,第一个在我们的例子中从未使用过。其余的功能及其目标如下:
-
Init(KeyGenerationParameters)函数:该函数的目标是初始化用于生成密钥的参数。 -
AsymmetricCipherKeyPair GenerateKeyPair()函数:顾名思义,该函数用于生成一对密钥。 -
ECMultiplier CreateBasePointMulitplier()函数:该函数返回一个定点乘数。 -
X9ECParameters IdentifyEllipticCurveByObjectIdentifier (DerObjectIdentifier object_identifier)函数:基于对象标识符,该函数返回符合 X9 格式的椭圆曲线的参数。 -
ECPublicKeyParameters GetCorrespondingPublicKey(ECPrivateKeyParameters private_key)函数:该函数是一个内部静态函数,其目的是根据作为私有参数为椭圆曲线设置的私钥,获得相应的公钥。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org;
namespace BCCase
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Generate private
/public key pair");
//** 1st case when the key size is 128 b
Console.WriteLine("CASE 1 - 128 Bytes\n");
GeneratePKeys(128);
//** 2nd case when the key size is 256 b
Console.WriteLine("\n\n\nCASE 2 - 256 Bytes\n");
GeneratePKeys(256);
}
public static void GeneratePKeys(int intSize)
{
//Generating p-128 keys 128 specifies strength
var keyPair = GenerateKeys(intSize);
TextWriter textWriter = new StringWriter();
Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new
Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
string privateKey = textWriter.ToString();
Console.WriteLine("\tThe private key is:");
Console.WriteLine("\t\t\t {0}", privateKey.ToString());
ECPrivateKeyParameters privateKeyParam =
(ECPrivateKeyParameters)keyPair.Private;
Console.WriteLine("\tD parameter: {0}",
privateKeyParam.D.ToString());
textWriter = new StringWriter();
pemWriter = new
Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
pemWriter.WriteObject(keyPair.Public);
pemWriter.Writer.Flush();
ECPublicKeyParameters publicKeyParam =
(ECPublicKeyParameters)keyPair.Public;
string publickey = textWriter.ToString();
Console.WriteLine("\nThe public key is:");
Console.WriteLine("\t\t\t{0}", publickey.ToString());
Console.WriteLine("\nX parameter: {0}",
publicKeyParam.Q.XCoord.ToBigInteger().ToString());
Console.WriteLine("Y parameter: {0}",
publicKeyParam.Q.YCoord.ToBigInteger().ToString());
}
public static AsymmetricCipherKeyPair GenerateKeys(int keySize)
{
//** we will choose ECDSA for generating the keys
var gen = new
Org.BouncyCastle.Crypto.Generators.
EllipticCurveKeyGenerator("ECDSA");
//** randomly generation
var secureRandom = new SecureRandom();
//Parameters creation using the random and keysize
var keyGenParam = new
KeyGenerationParameters(secureRandom,
keySize);
//** send the parameters for generating
gen.Init(keyGenParam);
//** generate the key pair
return gen.GenerateKeyPair();
}
}
}
Listing 10-2Generating Cryptographic Keys Using Bouncy Castle
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.TeleTrust;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.EC;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Multiplier;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Generators
{
class EllipticCurveKeyGenerator : IAsymmetricCipherKeyPairGenerator
{
private readonly string theAlgorithm;
private ECDomainParameters theParameters;
private DerObjectIdentifier publicKeyParamSet;
private SecureRandom random;
//** first constructor
public EllipticCurveKeyGenerator()
: this("EC")
{
}
//** second constructor
public EllipticCurveKeyGenerator(
string choosen_algorithm)
{
this.theAlgorithm = choosen_algorithm ??
throw new ArgumentNullException("algorithm");
}
public void Init(KeyGenerationParameters theParams)
{
if (theParams is ECKeyGenerationParameters
elliptic_curve_parameters)
{
this.publicKeyParamSet =
elliptic_curve_parameters.PublicKeyParamSet;
this.theParameters =
elliptic_curve_parameters.DomainParameters;
}
else
{
DerObjectIdentifier oid;
switch (theParams.Strength)
{
case 192:
oid = X9ObjectIdentifiers.Prime192v1;
break;
case 224:
oid = SecObjectIdentifiers.SecP224r1;
break;
case 128:
oid = SecObjectIdentifiers.SecP128r1;
break;
case 239:
oid = X9ObjectIdentifiers.Prime239v1;
break;
case 256:
oid = X9ObjectIdentifiers.Prime256v1;
break;
case 384:
oid = SecObjectIdentifiers.SecP384r1;
break;
case 521:
oid = SecObjectIdentifiers.SecP521r1;
break;
default:
throw new
InvalidParameterException("The key
size is not
defined or it is unknown.");
}
X9ECParameters ecps = IdentifyEllipticCurveByObjectIdentifier (oid);
this.publicKeyParamSet = oid;
this.theParameters = new ECDomainParameters(
ecps.Curve,
ecps.G,
ecps.N,
ecps.H,
ecps.GetSeed());
}
this.random = theParams.Random;
if (this.random == null)
{
this.random = new SecureRandom();
}
}
public AsymmetricCipherKeyPair GenerateKeyPair()
{
BigInteger n = theParameters.N;
BigInteger d;
int minWeight = n.BitLength >> 2;
for (; ; )
{
d = new BigInteger(n.BitLength, random);
if (d.CompareTo(BigInteger.Two) < 0 ||
d.CompareTo(n) >= 0)
continue;
if (WNafUtilities.GetNafWeight(d) < minWeight)
continue;
break;
}
ECPoint ellipticCurvePoint =
CreateBasePointMultiplier().
Multiply(theParameters.G, d);
if (publicKeyParamSet != null)
{
return new AsymmetricCipherKeyPair(
new ECPublicKeyParameters(theAlgorithm, ellipticCurvePoint, publicKeyParamSet),
new ECPrivateKeyParameters(theAlgorithm,
d,
publicKeyParamSet));
}
return new AsymmetricCipherKeyPair(
new ECPublicKeyParameters(theAlgorithm,
ellipticCurvePoint,
theParameters),
new ECPrivateKeyParameters(theAlgorithm,
d,
theParameters));
}
protected virtual ECMultiplier
CreateBasePointMultiplier()
{
return new FixedPointCombMultiplier();
}
internal static X9ECParameters
IdentifyEllipticCurveByObjectIdentifier
(DerObjectIdentifier
object_identifier)
{
X9ECParameters x9_elliptic_curve_parameters =
CustomNamedCurves.GetByOid(object_identifier);
if (x9_elliptic_curve_parameters == null)
{
x9_elliptic_curve_parameters =
ECNamedCurveTable.GetByOid(
object_identifier);
}
return x9_elliptic_curve_parameters;
}
internal static ECPublicKeyParameters
GetCorrespondingPublicKey(
ECPrivateKeyParameters private_key)
{
ECDomainParameters ellipticCurve_DomainParameters
= private_key.Parameters;
ECPoint ellipticCurvePoint =
new FixedPointCombMultiplier().
Multiply(ellipticCurve_DomainParameters.
G, private_key.D);
if (private_key.PublicKeyParamSet != null)
{
return new
ECPublicKeyParameters(
private_key.AlgorithmName,
ellipticCurvePoint,
private_key.PublicKeyParamSet);
}
return new
ECPublicKeyParameters(
private_key.AlgorithmName,
ellipticCurvePoint,
ellipticCurve_DomainParameters);
}
}
}
Listing 10-3The Generating of Elliptic Curve Keys
输出如图 10-3 所示。
图 10-3
钥匙
充气城堡装置
为了运行代码,您必须确保 Bouncy Castle 已正确安装在您的计算机上。为了实现这一点,首先你需要进入微软 Visual Studio ➤工具➤ NuGet 包经理➤管理 NuGet 包的解决方案,如图 10-4 所示。
图 10-4
充气城堡的安装
接下来的步骤是选择弹力城堡库,点击安装(见图 10-5 ,点击确定同意将要进行的更改(见图 10-6 )。图 10-7 显示了安装的确认。
图 10-7
安装确认
图 10-6
安装前预览更改
图 10-5
从列表中选择充气城堡进行安装
结论
在本章中,我们讨论了如何使用椭圆曲线加密技术,以及如何实现生成密钥和加密消息的实用解决方案。
在本章结束时,您现在已经了解了以下内容:
-
微软的区别 .NET 椭圆曲线支持和开源库,如弹力城堡
-
如何使用
ECDiffieHellmanCng类加密消息和生成密钥 -
如何使用 Bouncy Castle 库生成加密密钥对
在微软使用 ECC .NET 可能非常棘手,如果您不完全了解框架/库,代码的性能和质量可能会下降一大步。
文献学
-
伦斯特拉椭圆曲线密码。网上有:
https://en.wikipedia.org/wiki/Lenstra_elliptic-curve_factorization。 -
充气城堡。网上有:
www.bouncycastle.org/。
十一、基于格的密码学
在这一章中,我们将讨论基于格的密码学,它在密码学领域的重要性及其未来的挑战,以及我们如何设计和开发适合密码学应用的实用解决方案。
随着我们进入一个量子时代,量子密码原语的数量越来越多,基于格的密码的重要性是至关重要的。目前,基于格的构造是后量子密码术的重要候选。根据理论家的观点,RSA、Diffie-Hellman 或椭圆曲线密码系统等密码系统很容易被量子计算机攻击。一些基于格的密码构造在抵抗经典计算机和量子计算机攻击方面取得了很好的效果。
在实践中应用格作为一种加密解决方案并不是一件容易实现的任务,因为数学背景是复杂的,涉及到理解不同的抽象概念。在这一章中,我们将使用 NTRU-夏普库 [1 ],这是一个免费/开源库,包含公钥密码系统 [2 ]的 NTRU 实现。
数学背景
在这一节中,我们将提供一个基本概念和方法的快速概述,这些概念和方法构成了你应该知道的晶格数学背景的最小理论知识。
让我们考虑一下空间 ℝ n 和它的一个基础为( b 1 ,…, b n , b 1 ,…,bn∈*【ℝ】一个格表示与基构成线性组合的所有整数的集合,即格的一个例子是 ℤ * n ,它是通过经典基 ℝ 生成的。在密码学中,来自格装置的一个常见的困难假设是最短向量问题(SVP)。SVP 要求我们估计非零点阵向量的欧几里德距离的最小值。
使用格的密码系统之一是 NTRU [2 ],它可以抵抗使用 Schor 算法的攻击。NTRU 的 SVP 硬度假设包括将特定多项式分解成两个系数极低的多项式。注意,需要分解的特定多项式应该从截断的多项式环中定义。此外,以下是 NTRU 的密钥生成、加密和解密算法:
- 密钥生成。选择 n ∈ ℕ 和两个多项式 f 和 g ,它们的最大次数为n1,系数来自集合{ 1,0,1}。多项式 f 应该有一个附加的性质,即fpfq应该存在其中f∙fp= 1(mod p)和 f ∙ 私钥是k*priv=(f, f p , g )公钥是kpub=p∙*
** 加密。需要加密的消息是多项式 m ,其系数在{ 1,0,1}中。随机选择一个低系数的多项式 r ,由加密消息的发送者保密。 m 的加密计算为c=r∙h+m(mod q)。
* **Decryption** . To decrypt the message, the following computations need to be made:
*
*
实际实施
如上所述,为了实现和说明加密/解密的基本操作,我们使用了 NTRU-夏普库。该库的供应商做出了惊人的努力,并根据自由软件基金会发布的 GNU 通用公共许可证(许可证的第 3 版)的条款免费提供该库。NTRU-夏普是一个非常复杂的库(见图 11-1 ),包含了对密码学原语和基于格的原语的重要贡献。
图 11-1
NTRU 图书馆结构
实际实现的目的是展示如何使用该库来提供消息的加密和解密。要实现这一点,你需要熟悉NTRUEngine项目。为此,一旦项目加载到您喜欢的 IDE(集成开发环境)中,您需要导航到NTRU文件夹(参见图 11-1 )。在这里,您可以找到您需要的所有类、结构和方法/函数,例如NTRUParameters、NTRUParamSets、NTRUKeyPair、NTRUKeyGenerator、NTRUEncrypt和NTRUDecrypt。我们将仔细查看它们,并提供一些细节(见表 11-1 和表 11-2 )以便您快速了解这些类的用途及其功能/方法。
表 11-2
NTRU 方法
|字段、属性、构造函数、方法、函数名
|
描述
|
类型
|
| --- | --- | --- |
| NTRUParamSets.``APR2011743FAST | 该参数集提供 256 位安全性,但使用乘积形式多项式和 f=1+pF。 | 田 |
| NTRUKeyGenerator(new NTRUParameters()) | 用一组加密参数构造一个新实例 | 构造器 |
| GenerateKeyPair() | NTRU 密钥对容器 | 方法 |
| Initialize() | 初始化加密的密码。这个Initialize()方法只是为了加密。 | 方法 |
| Encrypt(byte[] Input) | 要加密的消息 | 方法 |
| Decrypt(byte[] Input) | 要解密的消息 | 方法 |
表 11-1
你上过课吗
|类别名
|
描述
|
| --- | --- |
| NTRUParameters | 创建、读取和写入NTRUEncrypt的参数设置 |
| NTRUParamSets | 一组预定义的 EES 加密参数集 |
| NTRUKeyPair | NTRU 密钥对容器 |
| NTRUKeyGenerator | 这个类实现了 NTRU 公钥加密系统的密钥对生成 |
| NTRUEncrypt | 一种 NTRU 非对称密码的实现 |
现在让我们看一下这个例子,了解它是如何工作的。例如,我们选择了一个简单的消息进行加密,如图 11-2 所示。
图 11-2
基于 NTRU 格的密码术加密实例
清单 11-1 包含了用于加密和解密的主要函数。请注意,要运行此示例,您应该做以下事情:
-
转到名为 Test 的项目,通过复制并粘贴清单 11-1 中的代码来修改名为
Program.cs的文件。 -
作为第二种选择,使用本书提供的 GitHub 库。
using System;
using Test.Tests.Arith;
using Test.Tests.Encode;
using Test.Tests.Encrypt;
using Test.Tests.Polynomial;
using System.Runtime.InteropServices;
using System.Diagnostics;
//** NTRU Engine libraries
using VTDev.Libraries.CEXEngine.
Crypto.Cipher.Asymmetric.Interfaces;
using VTDev.Libraries.CEXEngine.
Crypto.Cipher.Asymmetric.Encrypt.NTRU;
using VTDev.Libraries.CEXEngine.Tools;
using VTDev.Libraries.CEXEngine.Crypto.Prng;
using VTDev.Libraries.CEXEngine.Crypto;
//** The test project
using Test.Tests;
using System.Text;
using System.ComponentModel;
namespace Test
{
static class Program
{
static void Main(string[] args)
{
//** we will use as an example the
//** following example
//** "Welcome to Apress and Enjoy the adventure"
byte[] data = new byte[41] { 87, 101, 108, 99,
111, 109, 101, 32, 116, 111,
32, 65, 112, 114, 101, 115,
115, 32, 97, 110, 100, 32,
69, 110, 106, 111, 121, 32,
116, 104, 101, 32, 97, 100,
118, 101, 110, 116, 117, 114,
101 };
Console.WriteLine("Text to encrypt is:
{ Welcome to Apress
and Enjoy the adventure}");
Console.WriteLine("Byte representation (ASCII):
{0}\n\n", PrintByteArray(data));
//** Enc() function will do the
//** encryption and decryption
Enc();
Console.ReadKey();
}
private static void Enc()
{
//** the predefines parameters
NTRUParameters prm = NTRUParamSets.APR2011743FAST;
NTRUKeyPair keyPair;
byte[] enc, dec;
byte[] data = { 87, 101, 108, 99, 111, 109, 101,
32, 116, 111, 32, 65, 112, 114,
101, 115, 115, 32, 97, 110, 100,
32, 69, 110, 106, 111, 121, 32,
116, 104, 101, 32, 97, 100, 118,
101, 110, 116, 117, 114, 101 };
//** generate and display the key pair
using (NTRUKeyGenerator gen = new
NTRUKeyGenerator(prm))
{
keyPair = (NTRUKeyPair)gen.GenerateKeyPair();
Console.WriteLine("\t\tKey pair is:");
Console.WriteLine("\t\t\tPUBLIC KEY is: {0}",
PrintByteArray(keyPair.PublicKey.ToBytes()));
Console.WriteLine("\n\t\t\tPRIVATE KEY is:
{0}",
PrintByteArray(keyPair.PrivateKey.ToBytes()));
}
// encrypt a message
using (NTRUEncrypt ntru = new NTRUEncrypt(prm))
{
// initialize with public key for encryption
ntru.Initialize(keyPair.PublicKey);
// encrypt using public key
enc = ntru.Encrypt(data);
Console.WriteLine("\n\n\t\t\tTEXT ENCRYPTED:
{0}", PrintByteArray(enc));
}
// decrypt a message
using (NTRUEncrypt ntru = new NTRUEncrypt(prm))
{
// initialize with both keys for decryption
ntru.Initialize(keyPair);
// decrypt using key pair
dec = ntru.Decrypt(enc);
Console.WriteLine("\n\t\t\tTEXT DECRYPTED:
{0}", PrintByteArray(dec));
}
}
//** conversion of ascii to text
private static string ConvertASCII_To_Text(byte[] val)
{
//** Instantiate an ASCII encoding object
ASCIIEncoding ascii = new ASCIIEncoding();
foreach (var value in val)
Console.Write(value);
Console.WriteLine();
//** Decode the bytes and display
//** the resulting Unicode string.
String decoded = ascii.GetString(val);
return decoded.ToString();
}
//** perform parsing of the byte values byte by byte
public static string PrintByteArray(byte[] bytes)
{
var string_builder = new StringBuilder
("new byte[] { ");
foreach (var theByte in bytes)
{
string_builder.Append(theByte + " ");
}
string_builder.Append("}");
return string_builder.ToString();
}
}
}
Listing 11-1Encryption/Decryption Operation
Using NTRU-Sharp
结论
在这一章中,我们讨论了基于格的密码学及其重要性。在本章结束时,您现在已经了解了以下内容:
-
基于格的密码学的重要性及其对密码学未来的影响
-
如何应用 NTRU-夏普商业软件库
-
如何实现与网格相关的实用功能和方法
-
如何在复杂流程中使用
byte类型
文献学
-
NTRU 夏普。网上有:
https://github.com/Steppenwolfe65/NTRU-NET。 -
J.霍夫斯坦,j .皮弗和 J.H .西尔弗曼,“NTRU:一个基于环的公钥密码系统。”在 J. P .布勒(编)算法数论中。蚂蚁 1998。计算机科学讲义,第 1423 卷。斯普林格,柏林,海德堡。1998.
-
D.铜匠和 a .沙米尔,《晶格对 NTRU 的攻击》在 W. Fumy (ed) *密码学进展— EUROCRYPT '97。欧洲墓穴 1997。计算机科学讲义,第 1233 卷。*施普林格,柏林,海德堡。1997.
-
C.Gentry 和 M. Szydlo,“修改的 NTRU 签名方案的密码分析”密码学的进展——欧洲密码 2002 年。欧洲密码 2002。计算机科学讲义,第 2332 卷。斯普林格,柏林,海德堡。2002.*
十二、可搜索加密
可搜索加密(SE)允许将加密数据外包给可能不可信的第三方服务提供商,同时让用户能够以安全可靠的方式直接搜索加密数据。可搜索加密是同态加密的一个特例,这将在第十三章中讨论。
考虑以下情况。数据所有者 A 想要将一些文档存储在服务器上,但是同时接收者 B 需要能够访问和搜索这些数据。为了实现数据的这一属性,A 选择使用 B 的公钥加密文档,然后 A 将它们存储在服务器上。当 B 想要搜索包含特定关键字的文档时,比如说“programming”,他们使用“programming”关键字和他们的私钥生成一个名为 trapdoor 的值。然后,B 将陷门提交给服务器,服务器将根据算法执行搜索,并将符合标准的文档发送给 B。
下面是一个更实际的场景:一家公司正在开发一个软件解决方案,其中包括从客户那里获得的社会安全号(SSN)。规则和良好实践表明,SSN 在不参与数据处理时必须加密。另一方面,当员工需要搜索用户帐户时,他们使用 SSN。如果员工在工作时没有“看到”社会保障网络,该怎么办?使用可搜索的加密方案将使这成为可能。
有了这些例子,我们可以说可搜索加密是一种技术,通过这种技术,用户可以在加密的内容中搜索特定的数据。它可以应用于多个领域,例如医疗保健、医生处理患者的医疗文件、教育等等。
成分
可搜索加密方案有两种类型的组件:可搜索加密过程中涉及的实体和方案的算法。接下来我们将介绍这些组件。
实体
当一个软件解决方案被实现时,更多的方面应该在实现之前被澄清。谁将使用该应用?谁来维护?数据有哪些类型,谁可以访问它们?数据将存储在哪里?等等。从可搜索加密的角度来看,整个过程涉及以下实体:
-
数据所有者。数据所有者拥有一套由关键字描述的 n 文档 D = { D 1 ,…, D n 】。文档和关键词都将被外包出去,比如放在云服务器上。在将文档存储在服务器上之前,数据所有者将使用特定的加密方案对它们进行加密。数据所有者被认为是可信的实体。
-
数据用户。这是可以触发搜索过程的授权用户。该用户根据需要在加密内容中搜索的关键字生成陷门值。此外,如果资料使用者拥有私人密码匙,他们可将收到的文件解密。
-
服务器。服务器存储加密数据,并根据从数据用户处收到的陷门值执行搜索算法。服务器被认为是半可信的或诚实但好奇的,这意味着它按照指示执行搜索算法,但可以对提供给它的数据执行额外的分析。
注意,从上面的描述中,数据所有者可以是数据用户。
类型
可搜索加密方案可以根据密码类型分为两类:对称可搜索加密 (SSE)方案和带关键字搜索的公开加密 (PEKS)方案。在对称可搜索加密方案中,只有一个密钥用于加密或解密内容,在其他特定算法中也是如此,这一点您将在本节后面看到。具有关键字搜索的公共加密方案使用两种类型的密钥,即用于加密的公共密钥和用于解密的私有(秘密)密钥。
SSE 方案的算法是 [1
-
KeyGeneration。密钥生成算法由数据所有者运行。为了调用它,数据所有者需要一个安全参数 λ 作为输入,基于这个参数,算法将输出一种类型的密钥,即秘密密钥 SK 。 -
BuildIndex。构建索引结构的算法由数据所有者运行。该算法需要密钥 SK 和文档集 D 作为输入,输出是索引结构 I 。更确切地说,该算法从一个空的索引结构开始,然后它获取集合中的每个文档,并且对于每个文档,该算法向索引结构添加一些描述该文档的关键字。注意,在添加到索引结构之前,关键字是加密的(使用秘密密钥 SK )。 -
Trapdoor。数据用户运行这个算法。为了生成陷门值,该算法将搜索所基于的所需关键字 kw 和密钥 SK 作为输入,输出是陷门值 T kw 。请注意,陷门算法不只是对 kw 进行简单的加密。相反,它会添加一个噪波值或使用某种控制。 -
Search。服务器执行搜索算法。输入是之前生成的陷门值Tkw,索引结构 I 由BuildIndex算法产生。注意,搜索算法并不做 I 中Tkw的简单匹配。搜索算法要知道如何处理或者如何处理特殊值Tkw(别忘了Tkw不是简单的加密)。
如果服务器找到一份或多份符合标准的文件,它将把它们发送给数据用户;否则,它会发送一个消息。注意,上面没有提到加密和解密算法。数据所有者可以为文档本身和可搜索的加密方案选择不同的加密方案。这是因为文档不与可搜索加密方案的任何组件直接交互。上述所有算法仅适用于关键字和/或加密关键字的索引结构。
此外,PEKS 方案的算法是 [2
-
KeyGeneration。与 SSE 的密钥生成类似,数据所有者也运行这个算法。输入是安全参数 λ ,输出是一对密钥,公钥和私钥( PK 、 SK )。 -
Encryption。加密算法由数据所有者运行,输入是公钥 PK 和一个关键字 KW 。输出为 KW 的加密 SW 。 -
Trapdoor。这个算法类似于 SSE 的算法。数据用户使用他们的密钥 SK 和关键字 KW 作为输入来生成陷门值,以触发搜索。输出为陷门值 T KW 。 -
Test。服务器执行测试算法,将公钥 PK、加密文本 C (加密文本KW’)和陷门值 T KW 作为输入。如果*'=KW,测试算法的输出为 1,否则为 0。*
*对于陷门算法和测试算法也出现了相同的观察结果;它们不仅仅分别是常规加密和常规匹配。然而,上述 SSE 和 PEKS 方案的算法是在本领域的早期工作中介绍的,分别在 [1 和 [2 中介绍。随着时间的推移,随着更多类型的搜索可能性被探索,它们经历了转变。例如,一些作品允许多个关键字搜索,另一些作品允许基于关键字 [3 , 4 ]的模糊搜索(允许小的错别字或格式不一致),还有一些作品允许语义搜索(在这里,数据用户从查询关键字的语义字段接收包含关键字的文档) [5 ]等。其他工作以文档为中心,即直接在服务器上更新的文档,而不需要从服务器上检索、解密、更新、加密并再次存储在服务器上或直接在服务器上更新的索引结构 [6 ]。然而,在任何可搜索的加密方案中存在的算法是陷门和搜索/测试算法,当然还有加密和解密。
安全特征
可搜索加密需要保护的两件事情是搜索模式和访问模式。搜索模式是可以从两个搜索结果来自相同查询关键词的事实中获知的信息。访问模式是针对给定关键字 KW 返回的一组文档。此外,可搜索加密方案也应该满足关于搜索查询的安全要求。根据 [7 ],SE 方案应该提供受控搜索(只有授权用户可以提交搜索查询)、加密查询(查询搜索本身需要在被发送到服务器之前被加密)和查询隔离(服务器从它接收的查询中什么也不知道)。
SSE 方案应该确保索引结构不被破坏,因此应该抵抗 IND1-CKA 和/或 IND2-CKA(为索引选择的关键字攻击)。在 IND1-CKA 中,为所有文档选择相同数量的关键词,而在 IND2-CKA 中,文档可以由不同数量的关键词来描述。类似地,PEKS 方案应该抵抗选择关键字攻击(由攻击者和管理 PEKS 方案的结构之间的挑战组成)。
最近的安全需求是所谓的动态 SE 方案的前向前向和后向隐私,该方案支持直接在服务器上以加密格式插入、更新或删除一组文档或关键字的操作。向后和向前隐私涉及在插入/删除/更新过程中获知的信息。后向隐私处理当搜索基于在当前搜索之前被删除的文档中存在的关键字时获得的信息,而在前向隐私中,当前更新操作与先前操作无关。
简单的例子
然而,即使可搜索加密有很大的潜力,由于其抽象性,在常规应用中从零开始实现一个方案是非常困难的(错误的实现导致错误的加密,因此导致更少/没有安全性,并且可能消耗更多的资源)。Crypteron 1 开发了为数不多的提供可搜索加密工具的库之一。在他们的网站上,他们解释如何安装他们的库并把它们包含在项目中。在安装了所需的库之后,开发人员需要做的就是在允许基于关键字的搜索查询的类的字段上放置一个标志。受他们的例子的启发,清单 12-1 展示了如何将它应用到一个名为Student的类,并基于他们的个人代码进行搜索(参见清单 12-1 )。
public class Student
{
public int StudentId {get; set;}
[Secure]
public string StudentName {get; set;}
[Secure(Opt.Search)]
public string StudentPersonalCode {get; set;}
}
var queryKeywod =
SecureSearch.GetPrefix("123456789");
var resultStudent = myDatabase.Students.Where(p =>
p.StudentPersonalCode.StartsWith(searchPrefix))
Listing 12-1A Simple Example Framework for Searchable Encryption Implemention
在本例中,请注意为StudentPersonalCode字段启用可搜索属性的Opt.Search选项。在搜索之前,查询关键字由SecureSearch.GetPrefix处理。
复杂的例子
在下一个示例 [18 ]中,您将看到可搜索加密代表了一种高级且非常强大的加密技术,它为用户在加密文档中搜索关键字提供了优势。了解系统中的参与者非常重要。为此,我们对他们进行了如下分类:数据用户,他拥有一组文档 S = { D 1 ,…,Dn},通过生成密钥、加密密钥并将其存储在云服务器上,使系统准备就绪;数据所有者,他有在云服务器上提交搜索查询的可能性和优势;以及云服务器,存储加密文档并调用搜索算法。典型的 SE 技术包含以下随机化算法:
-
密钥生成(λ)→(Kp, K s ):密钥的生成基于安全参数。基于安全参数 λ ,生成一对公钥和私钥组成的集合,分别为(Kp)(Ks)。
-
加密(DI,Kp)→CI:算法会根据取公钥K的加密,输出加密后的文件 C i
-
build index(DI, w ,Kp)→I:一个构建索引算法有以下参数作为输入:文档 D i ,与文档关联的关键字 w,以及公钥K输出由基于文档和关键字之间的关联的索引结构表示。**
-
陷门 ( w 、Ks)→tw:陷门算法有两个参数作为输入:进行搜索的关键字和密钥。输出是一个陷门值 t w 。
-
搜索(tw, K p , I ) → C :搜索算法有以下参数:陷门值和公钥。输出表示带有关键字的加密文档
。
-
D ( C 、Ks)→D:解密算法将加密文件的 C 和密钥 K s 作为输入参数。输出由解密文档的集合
表示。
如今,椭圆曲线(见第十章)被用于区块链( [14 、 [15 )或物联网( [16 、 [17 )等重要课题。
在图 12-1 [18 ]中,你可以看到一个结合椭圆曲线加密和大数据环境的可搜索加密方案的真实例子(参见第十六章)。我们使用椭圆曲线数字签名算法(ECDSA)来保护通过电子学习平台向学生提供的课程。来自 ECDSA 算法的私钥被传递给可搜索的加密方案,并被用作安全参数( λ )。
图 12-1
一个实用的可搜索加密方案的例子 [18
没有可搜索加密的实现 .NET 或开源。我们深入研究了最近的研究,目前我们找不到任何作为库、模块或框架的真正实现。为了实现可搜索的加密方案,在执行实现之前应该考虑一些基本准则。指导方针如下:
-
软件应用的架构(服务器、数据库、服务等)。)
-
硬件设备以及如何为当前使用安全和加密机制的应用构建硬件设备
-
设计架构时,将可搜索的加密步骤表示为独立的算法,并且可以在整个网络基础架构的最终用户之间正确部署
如果你看一个可搜索的加密方案(见图 12-1 ),你可以看到它被分为多个步骤。每一步都有一个算法,可以作为可搜索加密方案的一个独立实例。这些实例可以表示为软件模块、软件服务,甚至物联网设备(例如英特尔 NUC 电脑或 Raspberry PI 设备)。软件模块或服务可以在分布式网络的用户之间分布和部署,例如云计算或用于中小型企业架构的普通网络基础设施。
以下算法 [18 描述了图右侧标题为 大数据环境 的的图 12-1 中的步骤。为了实现适当的实施,有必要且要求对作为单独和独立算法的步骤有清晰的印象。这些步骤是
-
( K O , K s ,PP)←key generation(1λ, P , S )。这表示由数据 O 的所有者运行的概率算法,该算法将采用安全参数 λ ,策略 P ,以及服务器 S 的身份,并且基于这些参数将输出所有者的秘密密钥 K O ,服务器密钥 K s
-
ID←build index(Daug, K O , PP )。这表示由所有者调用的概率算法。它将获取数据集Daug的描述和所有者的密钥( K O )并输出一个索引 I D 。
-
KU(U, λ ( u ), K O , PP )。这是一种概率算法,由所有者或调用,用于在电子学习平台系统中注册新用户。该算法将获取用户的新身份和用户的访问级别,以及所有者的 O 密钥,并为新用户输出秘密。
*** 陷门 ( ω ,λ(u)←查询 ( ω , K u )。这是一种确定性算法,由具有适当权限 λ ( u )的用户调用,以生成搜索查询。该算法将把关键字ω∈δ(其中δ表示关键字的字典)和用户的密钥作为输入,并输出查询令牌陷门(ω,λ(u)。
* **R** <sub>( **ω** ,**λ**(**u**)</sub>**←搜索** ( **陷门** <sub>( **ω** ,**λ**(**u**)</sub>, **I** <sub>**D**</sub> 确定性算法由服务器( *S* )运行,以在索引中搜索包含关键字 *ω* 的数据项。它将接受搜索查询和索引,并将搜索结果返回为***R***<sub>(***ω***, ***λ** ,*(**)**</sub>**,包括一组数据项的标识符 *d* <sub>*j*</sub> *λ* ( *u* ) 其中包含 *ω* 使得*λ*(*d*<sub>*j*</sub>)≤*λ*(*u*),其中 *λ* ( *u* )**
*** (**K**<sub>OT5)**←revoke user**(**u**, **K** <sub>**O**</sub> , **PP** )。概率算法由所有者*或*运行,以从系统中撤销特定用户。它将获取用户的 id 以及数据所有者和服务器的密钥,并为所有者和服务器输出新的密钥。</sub>
****
如果对于所有的 k ∈ ℕ ,对于所有的 K O , K S 由key gen(1λ, P ,对于所有的d 对于 BuildIndex 输出的所有ID(Daug, K O ),对于所有ω∈δ,对于所有U∈U λ ( u ), PP ),搜索(ID, T ω , λ ( u ) )
清单 12-2 中的例子是使用 LINQ 到 SQL 开发的,是实现图 12-1 中提出的可搜索加密方案的实用方法。必须提到的是,实现纯粹是指示性的,因为实现(框架、库等。)不存在。
public class KeyGeneration
{
//** Step 1
//** the algorithm from KeyGeneration step (algorithm)
//** are runned and invoked by the data owner
//** global variables
public string securityParameter = string.Empty();
public string ownerID = string.Empty();
public string policyContent = string.Empty();
public string serverIdentity = string.Empty();
//** the function will return the policy,
//** as a content or file
public string GetPolicy(IServiceCollection policyService)
{
policyService.AddAuthorization(policyChoices =>
{
policyChoices.AddPolicy("Policy content", policy
=>policy.Requirements.Add(new
UserPolicy()));
});
policyContent = policyChoices.ToString();
}
//** getting server identity can be tricky and it has
//** different meanings, such as the name of computer,
//** IP, active directory reference name etc...
//** For the current example we will use the hardware ID
public string GetServerIdentity()
{
ManagementObject hardwareID = new
ManagementObject(@"win32_logicaldisk.
deviceid=""c:""");
hardwareID.Get();
string idOfTheHardware = hardwareID
["VolumeSerialNumber"].ToString();
serverIdentity = ifOfTheHardware;
return serverIdentity;
}
//** class constructor
public KeyGeneration(){}
//** let's generate the secret key, server key
//** and public parameters
//** "#" represents the separator
public string ReturnParameters()
{
StringBuilder sbParameters = new StringBuilder();
sbParameters.Append(ownerSecretKey + "#" +
serverKey + "#" +);
publicParameters);
}
}
public class BuildIndex
{
//** Step 2
//** the algorithm from BuildIndex step (algorithm)
//** are runned and invoked by the data owner
//** constructor of the class
public void BuildIndex(){}
//** the function centralize the build index parameters
//** after their initialization and processing
public void UseBuildIndexParameters()
{
LinkedList descriptionDataSet =
new LinkedList();
string ownerPrivateKey = string.Empty();
string outputIndex = string.Empty();
}
//** simulation of getting the data set and their
//** descriptions
public LinkedList GetDataSet()
{
for(int i=0; i<dataSet.Length; i++)
{
LinkedList ll = new LinkedList();
ll.Items.Add(dataSet[i],description[i]);
}
}
//** getting the private of the owner
public string ownerPrivateKey()
{
string privateKey = string.Empty();
//** get the private key and work with it arround
return privateKey;
}
//** get the index
public string Index()
{
string index = string.Empy();
//** implement the query for getting
//** or generating the index
return index;
}
}
public class AddUser
{
//** Step 3
//** the algorithm from AddUser step (algorithm)
//** are runned and invoked by the data owner
//** constructor of the class AddUser
public string AddUser() {}
//** property for getting the identity of the user
//** see below the Class Student
public string IdentityOfTheUser()
string identity = string.Empty();
//** implement the way of getting
//** the identity of the user
return identity;
}
//** property for getting the owners key
public string OwnerSecretKey()
{
string secretKey = string.Empty();
//** implement the way of querying
//** for secret key
return secretKey;
}
public void AssignSecretKeyToUser()
{
Student stud = new
Student(OwnerSecretKey.ToString());
}
}
public class Query
{
//** Step 4
//** the algorithm from Query step (algorithm)
//** are runned and invoked by the user
//** constructor of the class Query
public void Query() {}
//** function for getting the keywords
public string Keyword()
{
string kw = string.Empty();
//** query for the keywords;
Return kw;
}
//** function for getting the secret key of the users
public string UserSecretKey()
{
string secretKey = string.Empty();
//** implement the way of querying
//** for secret key
return secretKey;
}
//** the generation of the output as query
//** token for the trapdoor
public string QueryToken()
{
string query_token = string.Empty();
//** generate and build
//** the query token for trapdoor
return query_token
}
}
public class Search
{
//** Step 5
//** the algorithm from Search step (algorithm)
//** are runned and invoked by the server
//** the constructor of the Search class
public void Search() {}
public string SearchQuery()
{
string query = string.Empty();
//** take the search query
return query;
}
public string Index()
{
string index = string.Empty();
//** take the search query
return index;
}
public string ReturnResult()
{
string result = string.Empty();
string setOfIdentifiers = string.Empty();
//** based on the search query and index,
//** get the set identifiers of the data items
setOfIdentifier = "query for identifiers";
//** build the result. "#" is the separator for
//** illustration purpose only
result = SearchQuery + "#" + Index;
return result;
}
}
public class RevokeUser
{
//** Step 6
//** the algorithm from Search step (algorithm)
//** are runned and invoked by the data owner
//** constructor of RevokeUser class
public void RevokeUser(){}
//** second constructor of the class
//** this can be implemented as a
//** solution for revoking a user
public void RevokeUser(string userID,
string secretKeyDataOwner,
string secretKeyServer)
{
//** implement the revoking process
//** output the new key for data owner
//** output the new key for server
}
}
public class Course
{
//** the db_panel represents an instance of the generated
//** DBML file which contains classes for each of tables
//** from the database
DatabaseDBPanel db_panel = new DatabaseDBPanel();
//** Class Courses it is a generated class and assigned
//** to the table Courses from the database
Courses c = new Courses();
//** student ID
string demoStudentID = "435663";
//** select the course ID based on the student
public string GetCourse()
{
//** select the courses for a
//** specific user (student)
var c = (from x in db_panel.Courses
where x.StudentID ==
demoStudentID.ToString()).Single();
return c.ToString();
}
}
public class Student
{
public string secretKey {get; set;}
public int StudentId {get; set;}
public string CourseID {get; set;}
[Secure]
public string StudentName {get; set;}
[Secure]
public string StudentIdentity {get; set;}
[Secure(Opt.Search)]
public string StudentPersonalCode {get; set;}
//** constructor of the class
public void Student(string secret_key)
{
secretKey = secret_key;
}
}
var queryKeywod =
SecureSearch.GetPrefix("123456789");
var resultStudent = myDatabase.Students.Where(p =>
p.StudentPersonalCode.StartsWith(searchPrefix))
Listing 12-2Implementation of Searchable Encryption Scheme
摘要
在本章中,描述了可搜索加密方案,并提供了一个支持可搜索加密的库的简单示例。
可搜索加密是同态加密的一个特例,在许多活动领域都有很大的潜力。如果您对可搜索加密的更多理论方面感兴趣,任何参考资料都提供了对 SE 的更深入的了解。有关伪代码的一些最新示例,请参考 [11 或 [12 。
文献学
-
E.J. Goh,“安全索引”IACR 密码学 ePrint 档案,2003,216。
-
D.Boneh,G. Di Crescenzo,R. Ostrovsky 和 G. Persiano,“使用关键字搜索的公钥加密”在国际密码技术理论与应用会议(第 506-522 页)。2004.斯普林格,柏林,海德堡。
-
J.李,王,王,曹,任,楼伟,“云计算中加密数据的模糊关键词搜索”。在 2010 年 IEEE INFOCOM 会议录(第 1-5 页)。2010.IEEE。
-
J.《容错可搜索加密》在 2009 IEEE 国际通信会议(第 1-6 页)。IEEE。2009.
-
J.赖,周,邓瑞宏,李彦宏,陈国光,“加密数据的表现性搜索”。第八届 ACM SIGSAC 信息、计算机和通信安全研讨会会议录(第 243-252 页)。2013.
-
R.Bost,“∑ oφoς:转发安全可搜索加密。”在2016 年 ACM SIGSAC 计算机与通信安全会议论文集(第 1143-1154 页)。2016.
-
D.X. Song、D. Wagner 和 A. Perrig,“加密数据搜索的实用技术”在 2000 年 IEEE 安全和隐私研讨会上。S & P 2000(第 44-55 页)。IEEE。2000.
-
J.Ghareh Chamani、D. Papadopoulos、C. Papamanthou 和 R. Jalili,“前向和后向私有对称可搜索加密的新构造”在2018 ACM SIGSAC 计算机与通信安全会议论文集(第 1038-1055 页)。2018.
-
C.左,孙,刘,邵,皮普日克,“动态可搜索对称加密的前向和强后向保密性。”在欧洲计算机安全研究研讨会(第 283-303 页)。施普林格,查姆。2019.
-
加密文档,
www.crypteron.com/docs/ -
C.马,谷耀辉,李。"实用的可搜索对称加密支持合取查询,没有关键字对结果模式泄漏."
-
南支持加密云数据逻辑查询的隐私保护模糊搜索方案。在移动网络和应用中,1-12。2010.
-
丹·博纳等人,《使用关键字搜索的公钥加密》密码技术理论与应用国际会议。施普林格,柏林,海德堡,2004。
-
欧内斯特·博纳和朱·石光,“区块链边缘计算环境中的隐私增强方案(PES)”(2019 年 10 月)IEEE 接入 2020。
-
Mohammad Shahriar Rahman 等人,“在宽松的信任假设下使用区块链进行可问责的跨境数据共享”2020 年 IEEE 工程管理汇刊。
-
C.Bö sch,P. Hartel,W. Jonker 和 A. Peter,“可证明安全的可搜索加密的调查”,载于 ACM Comput。调查,第 47 卷,第 2 期,第 1–51 页,2014 年。
-
Prabhat Kumar Panda 和 Sudipta Chattopadhyay。“物联网环境的安全相互认证协议”,载于可靠智能环境杂志(第 1-16 页),2020 年。
-
Mihailescu Marius Iulian、Nita Stefania Loredana 和 Pau Valentin Corneliu。"使用椭圆曲线加密和可搜索加密的电子学习系统框架."《电子学习和教育软件国际科学会议论文集》第 1 卷(第 545-552 页),2020 年。DOI: 10.12753/2066-026X-20-071。
*****