我没有密码学方面的经验,但是,由于没有其他人回答,我会试一试。
您的问题对我来说并不是很有意义,因此我决定在 JavaScript 中实现一个完整的 Elgamal,以便我可以在上下文中理解您的问题。这是我想出的:
// Abstract:
var Alphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \n𮃩∆";
Alphabet = Alphabet.split("");
var Crypto = function (alpha, gen, C) {
var p, B, encrypt, decrypt, f, g, modInv, modPow, toAlpha, to10;
toAlpha = function (x) {
var y, p, l, n;
if (x === 0) {
return "!!!!";
}
y = [];
n = 4;
n = Math.ceil(n);
while (n--) {
p = Math.pow(alpha.length, n);
l = Math.floor(x / p);
y.push(alpha[l]);
x -= l * p;
}
y = y.join("");
return y;
};
to10 = function (x) {
var y, p, n;
y = 0;
p = 1;
x = x.split("");
n = x.length;
while (n--) {
y += alpha.indexOf(x[n]) * p;
p *= alpha.length;
}
return y;
};
modInv = function (gen, mod) {
var v, d, u, t, c, q;
v = 1;
d = gen;
t = 1;
c = mod % gen;
u = Math.floor(mod / gen);
while (d > 1) {
q = Math.floor(d / c);
d = d % c;
v = v + q * u;
if (d) {
q = Math.floor(c / d);
c = c % d;
u = u + q * v;
}
}
return d ? v : mod - u;
};
modPow = function (base, exp, mod) {
var c, x;
if (exp === 0) {
return 1;
} else if (exp < 0) {
exp = -exp;
base = modInv(base, mod);
}
c = 1;
while (exp > 0) {
if (exp % 2 === 0) {
base = (base * base) % mod;
exp /= 2;
} else {
c = (c * base) % mod;
exp--;
}
}
return c;
};
p = 91744613;
C = parseInt(C, 10);
if (isNaN(C)) {
C = Math.round(Math.sqrt(Math.random() * Math.random()) * (p - 2) + 2);
}
B = modPow(gen, C, p);
decrypt = function (a) {
var d, x, y;
x = a[1];
y = modPow(a[0], -C, p);
d = (x * y) % p;
d = Math.round(d) % p;
return alpha[d - 2];
};
encrypt = function (key, d) {
var k, a;
k = Math.ceil(Math.sqrt(Math.random() * Math.random()) * 1E10);
d = alpha.indexOf(d) + 2;
a = [];
a[0] = modPow(key[1], k, key[0]);
a[1] = (d * modPow(key[2], k, key[0])) % key[0];
return a;
};
f = function (message, key) {
var n, x, y, w;
y = [];
message = message.split("");
n = message.length;
while (n--) {
x = encrypt(key, message[n]);
y.push(toAlpha(x[0]));
y.push(toAlpha(x[1]));
}
y = y.join("");
return y;
};
g = function (message) {
var n, m, d, x;
m = [];
n = message.length / 8;
while (n--) {
x = message[8 * n + 4];
x += message[8 * n + 5];
x += message[8 * n + 6];
x += message[8 * n + 7];
m.unshift(x);
x = message[8 * n];
x += message[8 * n + 1];
x += message[8 * n + 2];
x += message[8 * n + 3];
m.unshift(x);
}
x = [];
d = [];
n = m.length / 2;
while (n--) {
x[0] = m[2 * n];
x[1] = m[2 * n + 1];
x[0] = to10(x[0]);
x[1] = to10(x[1]);
d.push(decrypt(x));
}
message = d.join("");
return message;
};
return {
pubKey: [p, gen, B],
priKey: C,
decrypt: g,
encrypt: f
};
};
// Usage:
var Alice = Crypto(Alphabet, 69);
var Bob = Crypto(Alphabet, 69);
var message = "Hello!";
console.log(message);
// "Hello!"
message = Alice.encrypt(message, Bob.pubKey);
print(message);
// "Pl)7t&rfGueuL@|)H'P,*<K\.hxw+∆d*`?Io)lg~Adz-6xrR" or something like it.
message = Bob.decrypt(message);
console.log(message);
// "Hello!"
所以,基本上,Crypto 处理所有 Elgamal 算法,在需要时使用modPow。我认为 modPow 函数是您最初所追求的,不是吗?您最初发布的版本使用重复平方而不是普通求幂,大概是出于性能目的,但它们都相当快。
不过,我仍然不清楚为什么需要使用不同的算法来执行“m = a. b ^(p-1-x) mod p”。在实现我的 Elgamal 时我从来不需要这样的东西,所以我不确定这对应的是什么。我确实需要实现一个计算modular multiplicative inverse 的函数,我称之为modInv。那是你想要的吗?我使用了Extended Euclidean Algorithm 的精简版来制作它。
如果有帮助,请随时为您的项目复制我的部分或全部代码。
而且,如果您对此还有任何疑问,请问我!
编辑:请注意,此代码不适用于实际的生产级加密。这实际上只是算法的概念证明。然而,只要做一些工作,它就可以变得更加安全。告诉我。
编辑:要加密和解密文本,请执行以下操作:
新建Crypto对象对文本进行加密,然后保存:
var Alice=Crypto(Alphabet, 69);
这里,Alice 只是一些变量,Alphabet 是我在代码顶部定义的 29 个符号的字母表,69 是 primitive root mod 91744613。
然后,创建另一个 Crypto 对象来解密文本,然后保存:
var Bob=Crypto(Alphabet, 69);
虽然Bob 的创建方式与Alice 相同,但它们是不同的对象。 Bob 无法解密发给 Alice 的文本,Alice 也无法解密发给 Bob 的文本。
现在,使用Alice的加密方法对部分文本进行加密,并保存结果:
var codedMessage=Alice.encrypt("HELLO, WORLD.", Bob.pubKey);
这里,message 是一个空变量,"HELLO, WORLD." 是要加密的文本(或文本文件的内容)。 Bob.key 是 Bob 的公钥。我们必须在加密中使用 Bob 的密钥,以便 Bob(并且只有 Bob)可以解密文本。生成的加密文本将如下所示:"Pl)7t&rfGueuL@|)H'P,*<K\.hxw+∆d*?Io)lg~Adz-6xrR"`。请注意,即使使用相同的消息,每次都会生成不同的输出。它仍将始终解密为相同的值。
现在,理论上,我们可以通过任何我们想要的不安全通道发送此加密文本,并且没有人能够对其进行解码。然而,当 Bob 收到加密文本时,他可以对其进行解码。为此:
var plainMessage=Bob.decrypt(codedMessage);
现在,plainMessage 将包含文本 "HELLO, WORLD.",您可以阅读或做任何您想做的事情。
所以,只要这四行代码就可以做到:
var Alice=Crypto(Alphabet, 69);
var Bob=Crypto(Alphabet, 69);
var codedMessage=Alice.encrypt("HELLO, WORLD.", Bob.pubKey);
var plainMessage=Bob.decrypt(codedMessage);
// Now, plainMessage contains "HELLO, WORLD."
如果您特别想使用文本文件执行此操作,那么您可以将内容复制并粘贴到 javascript 中,或者您可以考虑将文本文件的内容加载到 javascript 中.要开始使用,请参阅 this SO 和 this HG。