I'm working on verifying a signature which public key is provided as
MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEMyHD625uvsmGq4C43cQ9BnfN2xslVT5V1nOmAMP6qaRRUll3PB1JYmgSm+62sosG
After a lot of research I think it is a ECDsaP192
standard key (Correct me if I'm wrong).
So the break down of the key would be
30 13
06 07 2A 86 48 CE 3D 02 01
06 08 2A 86 48 CE 3D 03 01 01
03 32 00
04
33 21 C3 EB 6E 6E BE C9 86 AB 80 B8 DD C4 3D 6 77 CD DB 1B 25 55 3E 55 // Qx, 24 bytes
D6 73 A6 0 C3 FA A9 A4 51 52 59 77 3C 1D 49 62 68 12 9B EE B6 B2 8B 6 // Qy, 24 bytes
I saw an example of a secp256r1 key which is very similar to my case but still I couldn't get it to work for me. My code:
private static readonly byte[] p192r1Prefix =
Convert.FromBase64String("MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAE");
private static readonly byte[] s_cngBlobPrefix = { 0x45, 0x43, 0x53, 0x31, 0x18, 0, 0, 0 };
void Main()
{
var pubkey = @"MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEMyHD625uvsmGq4C43cQ9BnfN2xslVT5V1nOmAMP6qaRRUll3PB1JYmgSm+62sosG";
var key = ImportECDsa256PublicKey(pubkey);
}
private static CngKey ImportECDsa256PublicKey(string base64)
{
byte[] subjectPublicKeyInfo = Convert.FromBase64String(base64);
byte[] prefix = p192r1Prefix;
byte[] cngBlob = new byte[s_cngBlobPrefix.Length + 48];
Buffer.BlockCopy(s_cngBlobPrefix, 0, cngBlob, 0, s_cngBlobPrefix.Length);
Buffer.BlockCopy(
subjectPublicKeyInfo,
p192r1Prefix.Length,
cngBlob,
s_cngBlobPrefix.Length,
48);
return CngKey.Import(cngBlob, CngKeyBlobFormat.EccPublicBlob); // Error: The parameter is incorrect.
}
Edit: Using BouncyCastle
void Main()
{
// Documentation https://developer.apple.com/documentation/storekit/skadnetwork/verifying_an_install_validation_postback
var applePublicKey = @"MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEMyHD625uvsmGq4C43cQ9BnfN2xslVT5V1nOmAMP6qaRRUll3PB1JYmgSm+62sosG";
var keyBytes = Convert.FromBase64String(applePublicKey);
var param = GetPublicKeyParam(keyBytes);
var dataStr = "2.0" + '\u2063' + "com.example" + '\u2063' + "42" + '\u2063' + "525463029" + '\u2063' + "6aafb7a5-0170-41b5-bbe4-fe71dedf1e28" + '\u2063' + "1" + '\u2063' + "1234567891";
var data = Encoding.UTF8.GetBytes(dataStr);
var signature = "MDYCGQCsQ4y8d4BlYU9b8Qb9BPWPi+ixk/OiRysCGQDZZ8fpJnuqs9my8iSQVbJO/oU1AXUROYU=";
var sigBytes = Convert.FromBase64String(signature);
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
signer.Init(false, param);
signer.BlockUpdate(data, 0, dataStr.Length);
Console.WriteLine(signer.VerifySignature(sigBytes));
}
private ECPublicKeyParameters GetPublicKeyParam(byte[] publicKeyBytes)
{
// parse based on asn1 format the content of the certificate
var asn1 = (Asn1Sequence)Asn1Object.FromByteArray(publicKeyBytes);
var at1 = (DerBitString)asn1[1];
var xyBytes = at1.GetBytes();
//retrieve preddefined parameters for P192(?) curve
X9ECParameters x9 = NistNamedCurves.GetByName("P-192");
//establish domain we will be looking for the x and y
ECDomainParameters domainParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
ECPublicKeyParameters publicKeyParams = new ECPublicKeyParameters(x9.Curve.DecodePoint(xyBytes), domainParams);
return publicKeyParams;
}