struct PKCS1v1_5Signature [src]

RFC 3447 8.2 RSASSA-PKCS1-v1_5

Members

Source

pub const PKCS1v1_5Signature = 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 em_dec = try encrypt(modulus_len, sig, public_key); const em = try EMSA_PKCS1_V1_5_ENCODE(msg, modulus_len, Hash); if (!std.mem.eql(u8, &em_dec, &em)) return error.InvalidSignature; } fn EMSA_PKCS1_V1_5_ENCODE(msg: []const []const u8, comptime emLen: usize, comptime Hash: type) VerifyError![emLen]u8 { comptime var em_index = emLen; var em: [emLen]u8 = undefined; // 1. Apply the hash function to the message M to produce a hash value // H: // // H = Hash(M). // // If the hash function outputs "message too long," output "message // too long" and stop. var hasher: Hash = .init(.{}); for (msg) |part| hasher.update(part); em_index -= Hash.digest_length; hasher.final(em[em_index..]); // 2. Encode the algorithm ID for the hash function and the hash value // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with // the Distinguished Encoding Rules (DER), where the type DigestInfo // has the syntax // // DigestInfo ::= SEQUENCE { // digestAlgorithm AlgorithmIdentifier, // digest OCTET STRING // } // // The first field identifies the hash function and the second // contains the hash value. Let T be the DER encoding of the // DigestInfo value (see the notes below) and let tLen be the length // in octets of T. const hash_der: []const u8 = &switch (Hash) { crypto.hash.Sha1 => .{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, }, crypto.hash.sha2.Sha224 => .{ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c, }, crypto.hash.sha2.Sha256 => .{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, }, crypto.hash.sha2.Sha384 => .{ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30, }, crypto.hash.sha2.Sha512 => .{ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40, }, else => @compileError("unreachable"), }; em_index -= hash_der.len; @memcpy(em[em_index..][0..hash_der.len], hash_der); // 3. If emLen < tLen + 11, output "intended encoded message length too // short" and stop. // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets // with hexadecimal value 0xff. The length of PS will be at least 8 // octets. em_index -= 1; @memset(em[2..em_index], 0xff); // 5. Concatenate PS, the DER encoding T, and other padding to form the // encoded message EM as // // EM = 0x00 || 0x01 || PS || 0x00 || T. em[em_index] = 0x00; em[1] = 0x01; em[0] = 0x00; // 6. Output EM. return em; } }