将 ElGamal 加密从加密数字转换为字符串
Converting ElGamal encryption from encrypting numbers to strings
我有以下 ElGamal 加密方案
const forge = require('node-forge');
const bigInt = require("big-integer");
// Generates private and public keys
function keyPairGeneration(p, q, g) {
var secretKey = bigInt.randBetween(2, q.minus(2));
var publicKey = g.modPow(secretKey, p);
const keys = {
secret: secretKey,
public: publicKey
}
return keys;
}
// Generates a proxy and a user key
function generateProxyKeys(secretKey) {
const firstKey = bigInt.randBetween(1, secretKey);
const secondKey = secretKey.minus(firstKey);
const keys = {
firstKey: firstKey,
secondKey: secondKey
}
return keys;
}
// Re-encrypts
function preEncrypt(p, q, g, m, publicKey) {
const k = bigInt.randBetween(1, q.minus(1));
const c1 = g.modPow(k, p);
// g^x = publicKey
// m.publicKey^k
const c2 = bigInt(m).multiply(publicKey.modPow(k, p)).mod(p);
const c = {
c1: c1,
c2: c2
}
return c;
}
function preDecrypt(p, c1, c2, key) {
// (mg^xr) / (g^rx1)
var decrypt = c2.multiply(c1.modPow(key, p).modInv(p)).mod(p);
return decrypt;
}
这对数字很好用。但是,我希望能够使用它来加密字符串(顺便说一句,它不是常规的 ElGamal,我不认为区别在于与此相关,但有关更多详细信息,请参阅 )
我考虑过将字符串转换为整数,运行 加密,然后在需要时转换回字符串。我找不到在 JS 中执行此操作的方法(有 this question posted here but the code didn't work). There is 但它在 Java 中,并且 JS 中的 BigInt 实现未提供其中提到的方法。
有没有简单的方法可以将字符串转换为 BigInt?
任意长的消息
不应该使用非对称加密来加密任意长度的消息,因为它比对称加密慢得多。因此,我们可以对实际消息使用对称加密,对加密消息的密钥使用非对称加密。
对于任意大小的消息基本上有两种方式:
如果素数 p
足够大,适合 AES 等对称密码的通用密钥大小,那么您可以简单地生成随机 AES 密钥(128、192 或 256位)并使用 AES 派生方案(例如 AES-GCM)来加密您的消息。之后,您从 AES 密钥解码一个数字(使用 fromArray
) to be used as m
in your ElGamal-like encryption scheme. This is called hybrid encryption.
无论质数p
有多大,你总是可以生成一个1
到p-1
范围内的随机m
数并使用产生你的非对称密文。之后,可以将之前生成的m
,编码成字节数组(使用toString(16)
to produce a Hex-encoded string and then simply parse it as Hex for the hashing) and hash it with a cryptographic hash function such as SHA-256 to get your AES key. Then you can use the AES key to encrypt the message with a symmetric scheme like AES-GCM. This is called key encapsulation.
您需要注意的主要剩余事项是数据格式:如何序列化密文的非对称部分和对称部分的数据?您如何读回它们才能始终 区分它们?那里有很多可能的解决方案。
短信
如果您要加密的邮件的最大大小小于您使用的素数,则您不需要上述两种方法。您只需要获取消息的字节表示并将其转换为一个大整数。像这样:
var arr = Array.prototype.slice.call(Buffer.from("some message"), 0);
var message = bigInt.fromArray(arr, 256);
这是一个big endian encoding。
这只有在你的质数足够大时才有意义should be for security。
我有以下 ElGamal 加密方案
const forge = require('node-forge');
const bigInt = require("big-integer");
// Generates private and public keys
function keyPairGeneration(p, q, g) {
var secretKey = bigInt.randBetween(2, q.minus(2));
var publicKey = g.modPow(secretKey, p);
const keys = {
secret: secretKey,
public: publicKey
}
return keys;
}
// Generates a proxy and a user key
function generateProxyKeys(secretKey) {
const firstKey = bigInt.randBetween(1, secretKey);
const secondKey = secretKey.minus(firstKey);
const keys = {
firstKey: firstKey,
secondKey: secondKey
}
return keys;
}
// Re-encrypts
function preEncrypt(p, q, g, m, publicKey) {
const k = bigInt.randBetween(1, q.minus(1));
const c1 = g.modPow(k, p);
// g^x = publicKey
// m.publicKey^k
const c2 = bigInt(m).multiply(publicKey.modPow(k, p)).mod(p);
const c = {
c1: c1,
c2: c2
}
return c;
}
function preDecrypt(p, c1, c2, key) {
// (mg^xr) / (g^rx1)
var decrypt = c2.multiply(c1.modPow(key, p).modInv(p)).mod(p);
return decrypt;
}
这对数字很好用。但是,我希望能够使用它来加密字符串(顺便说一句,它不是常规的 ElGamal,我不认为区别在于与此相关,但有关更多详细信息,请参阅
我考虑过将字符串转换为整数,运行 加密,然后在需要时转换回字符串。我找不到在 JS 中执行此操作的方法(有 this question posted here but the code didn't work). There is
有没有简单的方法可以将字符串转换为 BigInt?
任意长的消息
不应该使用非对称加密来加密任意长度的消息,因为它比对称加密慢得多。因此,我们可以对实际消息使用对称加密,对加密消息的密钥使用非对称加密。
对于任意大小的消息基本上有两种方式:
如果素数
p
足够大,适合 AES 等对称密码的通用密钥大小,那么您可以简单地生成随机 AES 密钥(128、192 或 256位)并使用 AES 派生方案(例如 AES-GCM)来加密您的消息。之后,您从 AES 密钥解码一个数字(使用fromArray
) to be used asm
in your ElGamal-like encryption scheme. This is called hybrid encryption.无论质数
p
有多大,你总是可以生成一个1
到p-1
范围内的随机m
数并使用产生你的非对称密文。之后,可以将之前生成的m
,编码成字节数组(使用toString(16)
to produce a Hex-encoded string and then simply parse it as Hex for the hashing) and hash it with a cryptographic hash function such as SHA-256 to get your AES key. Then you can use the AES key to encrypt the message with a symmetric scheme like AES-GCM. This is called key encapsulation.
您需要注意的主要剩余事项是数据格式:如何序列化密文的非对称部分和对称部分的数据?您如何读回它们才能始终 区分它们?那里有很多可能的解决方案。
短信
如果您要加密的邮件的最大大小小于您使用的素数,则您不需要上述两种方法。您只需要获取消息的字节表示并将其转换为一个大整数。像这样:
var arr = Array.prototype.slice.call(Buffer.from("some message"), 0);
var message = bigInt.fromArray(arr, 256);
这是一个big endian encoding。
这只有在你的质数足够大时才有意义should be for security。