struct PSSSignature [src]

RFC 3447 8.1 RSASSA-PSS

Members

Source

pub const PSSSignature = struct { pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8 { var result: [modulus_len]u8 = undefined; @memcpy(result[0..msg.len], msg); @memset(result[msg.len..], 0); return result; } pub const VerifyError = EncryptError || error{InvalidSignature}; pub fn verify( comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type, ) VerifyError!void { try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash); } pub fn concatVerify( comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const []const u8, public_key: PublicKey, comptime Hash: type, ) VerifyError!void { const mod_bits = public_key.n.bits(); const em_dec = try encrypt(modulus_len, sig, public_key); try EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash); } fn EMSA_PSS_VERIFY(msg: []const []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type) VerifyError!void { // 1. If the length of M is greater than the input limitation for // the hash function (2^61 - 1 octets for SHA-1), output // "inconsistent" and stop. // All the cryptographic hash functions in the standard library have a limit of >= 2^61 - 1. // Even then, this check is only there for paranoia. In the context of TLS certificates, emBit cannot exceed 4096. if (emBit >= 1 << 61) return error.InvalidSignature; // emLen = \ceil(emBits/8) const emLen = ((emBit - 1) / 8) + 1; std.debug.assert(emLen == em.len); // 2. Let mHash = Hash(M), an octet string of length hLen. var mHash: [Hash.digest_length]u8 = undefined; { var hasher: Hash = .init(.{}); for (msg) |part| hasher.update(part); hasher.final(&mHash); } // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. if (emLen < Hash.digest_length + sLen + 2) { return error.InvalidSignature; } // 4. If the rightmost octet of EM does not have hexadecimal value // 0xbc, output "inconsistent" and stop. if (em[em.len - 1] != 0xbc) { return error.InvalidSignature; } // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, // and let H be the next hLen octets. const maskedDB = em[0..(emLen - Hash.digest_length - 1)]; const h = em[(emLen - Hash.digest_length - 1)..(emLen - 1)][0..Hash.digest_length]; // 6. If the leftmost 8emLen - emBits bits of the leftmost octet in // maskedDB are not all equal to zero, output "inconsistent" and // stop. const zero_bits = emLen * 8 - emBit; var mask: u8 = maskedDB[0]; var i: usize = 0; while (i < 8 - zero_bits) : (i += 1) { mask = mask >> 1; } if (mask != 0) { return error.InvalidSignature; } // 7. Let dbMask = MGF(H, emLen - hLen - 1). const mgf_len = emLen - Hash.digest_length - 1; var mgf_out_buf: [512]u8 = undefined; if (mgf_len > mgf_out_buf.len) { // Modulus > 4096 bits return error.InvalidSignature; } const mgf_out = mgf_out_buf[0 .. ((mgf_len - 1) / Hash.digest_length + 1) * Hash.digest_length]; var dbMask = try MGF1(Hash, mgf_out, h, mgf_len); // 8. Let DB = maskedDB \xor dbMask. i = 0; while (i < dbMask.len) : (i += 1) { dbMask[i] = maskedDB[i] ^ dbMask[i]; } // 9. Set the leftmost 8emLen - emBits bits of the leftmost octet // in DB to zero. i = 0; mask = 0; while (i < 8 - zero_bits) : (i += 1) { mask = mask << 1; mask += 1; } dbMask[0] = dbMask[0] & mask; // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not // zero or if the octet at position emLen - hLen - sLen - 1 (the // leftmost position is "position 1") does not have hexadecimal // value 0x01, output "inconsistent" and stop. if (dbMask[mgf_len - sLen - 2] != 0x00) { return error.InvalidSignature; } if (dbMask[mgf_len - sLen - 1] != 0x01) { return error.InvalidSignature; } // 11. Let salt be the last sLen octets of DB. const salt = dbMask[(mgf_len - sLen)..]; // 12. Let // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. if (sLen > Hash.digest_length) { // A seed larger than the hash length would be useless return error.InvalidSignature; } var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined; var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen]; std.mem.copyForwards(u8, m_p, &([_]u8{0} ** 8)); std.mem.copyForwards(u8, m_p[8..], &mHash); std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt); // 13. Let H' = Hash(M'), an octet string of length hLen. var h_p: [Hash.digest_length]u8 = undefined; Hash.hash(m_p, &h_p, .{}); // 14. If H = H', output "consistent". Otherwise, output // "inconsistent". if (!std.mem.eql(u8, h, &h_p)) { return error.InvalidSignature; } } fn MGF1(comptime Hash: type, out: []u8, seed: *const [Hash.digest_length]u8, len: usize) ![]u8 { var counter: u32 = 0; var idx: usize = 0; var hash = seed.* ++ @as([4]u8, undefined); while (idx < len) { std.mem.writeInt(u32, hash[seed.len..][0..4], counter, .big); Hash.hash(&hash, out[idx..][0..Hash.digest_length], .{}); idx += Hash.digest_length; counter += 1; } return out[0..len]; } }