fix pkcs#1 padding in rsa for sha1

This commit is contained in:
0xturboblitz
2024-06-11 23:14:00 +02:00
parent 28fd6f9bcd
commit ea36c775f1
3 changed files with 165 additions and 10 deletions

View File

@@ -1,8 +1,7 @@
pragma circom 2.1.5;
include "@zk-email/circuits/helpers/rsa.circom";
include "./utils/rsaPkcs1.circom";
include "@zk-email/circuits/helpers/extract.circom";
// include "@zk-email/circuits/helpers/sha.circom";
include "./utils/Sha1BytesStatic.circom";
include "./utils/Sha1Bytes.circom";
include "dmpierre/sha1-circom/circuits/sha1.circom";
@@ -78,10 +77,6 @@ template PassportVerifier_sha1WithRSAEncryption_65537(n, k, max_datahashes_bytes
for (var i = 160; i < n * msg_len; i++) {
eContentHash[i \ n].in[i % n] <== 0;
}
for (var i=0; i< msg_len; i++ ) {
log("eContentHash", eContentHash[i].out);
}
// verify eContentHash signature
// component rsa = RSAVerify65537(64, 32);

View File

@@ -0,0 +1,160 @@
pragma circom 2.1.5;
include "@zk-email/circuits/helpers/fp.circom";
// Computes base^65537 mod modulus
// Does not necessarily reduce fully mod modulus (the answer could be
// too big by a multiple of modulus)
template FpPow65537Mod(n, k) {
signal input base[k];
// Exponent is hardcoded at 65537
signal input modulus[k];
signal output out[k];
component doublers[16];
component adder = FpMul(n, k);
for (var i = 0; i < 16; i++) {
doublers[i] = FpMul(n, k);
}
for (var j = 0; j < k; j++) {
adder.p[j] <== modulus[j];
for (var i = 0; i < 16; i++) {
doublers[i].p[j] <== modulus[j];
}
}
for (var j = 0; j < k; j++) {
doublers[0].a[j] <== base[j];
doublers[0].b[j] <== base[j];
}
for (var i = 0; i + 1 < 16; i++) {
for (var j = 0; j < k; j++) {
doublers[i + 1].a[j] <== doublers[i].out[j];
doublers[i + 1].b[j] <== doublers[i].out[j];
}
}
for (var j = 0; j < k; j++) {
adder.a[j] <== base[j];
adder.b[j] <== doublers[15].out[j];
}
for (var j = 0; j < k; j++) {
out[j] <== adder.out[j];
}
}
template RSAPad(n, k) {
signal input modulus[k];
signal input base_message[k];
signal output padded_message[k];
var base_len = 280;
var msg_len = 160;
signal padded_message_bits[n*k];
component modulus_n2b[k];
component base_message_n2b[k];
signal modulus_bits[n*k];
signal base_message_bits[n*k];
for (var i = 0; i < k; i++) {
base_message_n2b[i] = Num2Bits(n);
base_message_n2b[i].in <== base_message[i];
for (var j = 0; j < n; j++) {
base_message_bits[i*n+j] <== base_message_n2b[i].out[j];
}
modulus_n2b[i] = Num2Bits(n);
modulus_n2b[i].in <== modulus[i];
for (var j = 0; j < n; j++) {
modulus_bits[i*n+j] <== modulus_n2b[i].out[j];
}
}
for (var i = msg_len; i < n*k; i++) {
base_message_bits[i] === 0;
}
for (var i = 0; i < msg_len; i++) {
padded_message_bits[i] <== base_message_bits[i];
}
for (var i = base_len; i < base_len + 8; i++) {
padded_message_bits[i] <== 0;
}
for (var i = msg_len; i < base_len; i++) {
padded_message_bits[i] <== (0x3021300906052b0e03021a05000414 >> (i - msg_len)) & 1;
}
component modulus_zero[(n*k + 7 - (base_len + 8))\8];
{
var modulus_prefix = 0;
for (var i = n*k - 1; i >= base_len + 8; i--) {
if (i+8 < n*k) {
modulus_prefix += modulus_bits[i+8];
if (i % 8 == 0) {
var idx = (i - (base_len + 8)) / 8;
modulus_zero[idx] = IsZero();
modulus_zero[idx].in <== modulus_prefix;
padded_message_bits[i] <== 1-modulus_zero[idx].out;
} else {
padded_message_bits[i] <== padded_message_bits[i+1];
}
} else {
padded_message_bits[i] <== 0;
}
}
}
// The RFC guarantees at least 8 octets of 0xff padding.
assert(base_len + 8 + 65 <= n*k);
for (var i = base_len + 8; i < base_len + 8 + 65; i++) {
padded_message_bits[i] === 1;
}
component padded_message_b2n[k];
for (var i = 0; i < k; i++) {
padded_message_b2n[i] = Bits2Num(n);
for (var j = 0; j < n; j++) {
padded_message_b2n[i].in[j] <== padded_message_bits[i*n+j];
}
padded_message[i] <== padded_message_b2n[i].out;
}
}
template RSAVerify65537(n, k) {
signal input signature[k];
signal input modulus[k];
signal input base_message[k];
component padder = RSAPad(n, k);
for (var i = 0; i < k; i++) {
padder.modulus[i] <== modulus[i];
padder.base_message[i] <== base_message[i];
}
// Check that the signature is in proper form and reduced mod modulus.
component signatureRangeCheck[k];
component bigLessThan = BigLessThan(n, k);
for (var i = 0; i < k; i++) {
signatureRangeCheck[i] = Num2Bits(n);
signatureRangeCheck[i].in <== signature[i];
bigLessThan.a[i] <== signature[i];
bigLessThan.b[i] <== modulus[i];
}
bigLessThan.out === 1;
component bigPow = FpPow65537Mod(n, k);
for (var i = 0; i < k; i++) {
bigPow.base[i] <== signature[i];
bigPow.modulus[i] <== modulus[i];
}
// By construction of the padding, the padded message is necessarily
// smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced.
for (var i = 0; i < k; i++) {
log("bigPow.out[i]: ", bigPow.out[i]);
log("padder.padded_message[i]: ", padder.padded_message[i]);
bigPow.out[i] === padder.padded_message[i];
}
}

View File

@@ -1,11 +1,11 @@
// Copied from zk-email cuz it uses crypto so can't import it here.
export function shaPad(signatureAlgorithm: string, prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
// if (signatureAlgorithm == 'sha1WithRSAEncryption') {
// return sha1Pad(prehash_prepad_m, maxShaBytes);
// } else {
if (signatureAlgorithm == 'sha1WithRSAEncryption') {
return sha1Pad(prehash_prepad_m, maxShaBytes);
} else {
return sha256Pad(prehash_prepad_m, maxShaBytes);
// }
}
}
// Puts an end selector, a bunch of 0s, then the length, then fill the rest with 0s.