跨平台的 RSA 签名不一致
Inconsistent RSA signature across platforms
我正在创建一个许可证密钥生成器,RSA 签署 base64 编码的许可证密钥数据并将签名附加到许可证 data.On 最终用户端签名使用捆绑的 public 密钥进行验证application.We 在 .net 上有应用程序 运行,php、java 和其他 platforms.License 模型应该对所有人都相同。
现在 trouble:I 已经使用内置的加密提供程序在 C# 中创建了 2048 位 public/private 密钥,并以 XML 格式导出密钥以获得 b64 中透明的密钥 BigInteger 组件 encoding.License密钥生成器应该在 php 中工作,我正在使用 phpseclib 导入 XML 密钥并签署 data.Php 代码:
function sign($data)
{
$RSA_PRIVATE_KEY = "<RSAKeyValue>
<Modulus>oPmCaLewqKTkRPpKLHz+9hEbrUbVdKNkIxzm4h5/wmuId6PSx6ntV2T44/NSzfx56LffyXvzx27GYEKk4zffpPYKdRIGReZVqfl2U5K3jcuv0h4657ge0nZ5W9vrYMDSFjgtZOSw8t2opWC8IZVUI3X9W8mp1Z3xqtwREpLC/kV0YE1Kmem8k8B4Tv1+qj5C6oPJjhy+T3JipYOQIyVRUoCdo3EHpDQ6K7twKD+Si/rASHyvoCJZTPvWI1w9y9FD8CxstkY7+ap8J9DMczyiFsE4kJtziBKZFph4ZRqz4kSA0TXj0lXhGEAcn1IDjhV5W37PdsWOkUTxBH7Bm7mpuw==</Modulus>
<Exponent>AQAB</Exponent>
<P>xU8K0Z1Mn0cLOHrwMIujXvtJbXpmjFfyOkm+WkeNV2hjDmdgMibJJvhqPEYPSabEHF4us8H4IeEqeInGK04LrYmbe3IVgmuGdpacR01WISbqXiarsKbcHkR65mfotQmxay/n3Swi8hN9yTanSJyhoHFBiJ0qYM0VNdamu7LDeGk=</P>
<Q>0Nukxy2o/o7z6NeR9g+dUcOQzXfWS2Bu4vAXyHGpJArGcIzl4Z2jNuUztGj5sO5b+9SQs4tgijsjbsEQUNN7R1+PB7Zwc50PvGgEvGaIJkPphGoJMNCw4Q2I8tNPb86cEd4WLJ8E6ad93vX0tyZAnn3LrjPg3Bvvxtq157jZLIM=</Q>
<DP>tGRV0dtsyFrdyV+s5dVlIlvAgFVeGIX3so7leAjfEsEff3XIH1ISqoyIJF8xbvcHaaA6NqLqx57jg50DD2iliJ29B5oATGMeZqHAc/gi/OBlensEkdecfBfD/Y+W1J3uFb+Qz0ehE436fNJ5EwwRQW0Kq2p16lbWQ4jim80OpbE=</DP>
<DQ>vML2bumuhbrvaK6EBa5hEce9dGXtcJyMO2ChLhDDvIZciNZe4YUWQQPvsgr6OFWFHtojmZHLQ8NlJ7EnrNUl4wDThTX29haqZS5hsWC9hk/0mi83dT33zr7r2gLvFW7XETL2OYfS6dXt5ffHH0xcNKIe1qeef3BkSgXbR72B0j8=</DQ>
<InverseQ>TffUf2HXQOmVEUo6rinASIOJOfwfucd+MjwDaK61bISFY5J2n3MYRX4wEiFxXlcYgXnR9CsbwRVhUDIDzLuB+ykAG62LkbqCKUYjzyN3RDbc/MSj/sXSw60pTc4DesVhQlumd0zGUOxsFkjOlUowxwIDENiSVFew1IfAOZiakpk=</InverseQ>
<D>AKHPgpxrXn4nQfi+9HsZKoYurE4sOw+ug6TIE03jWolpjm606SvK+XOKtqUXR3pyUBjzZqsh7eqKxN3+H8DxvogTdRo5BBU/c4dokN4b8maWWNDdkliwEPYoy9Tf5mVbbdLn+rlwfcOjtzfbWpZnhNbLGTfVfuKRNwaI2qB7kNwGB1fd1t4xMLWNozgoxFuiiKFbJKmLEj9zHP/KqjEnOH/zEuUBnXiqGMnCMmD7KnD5WqcqSDOahn0TBFlMxV+9Ul2447bu5LTGWhm3RBPEGgtjMboKC3PlgqwYDpC2gbzX5ZsBNCiuGgumxBHgOfAIOVzI01MZTFEpTcTt3BUrwQ==</D>
</RSAKeyValue>";
$RSA = new Crypt_RSA();
$RSA->loadKey($RSA_PRIVATE_KEY, CRYPT_RSA_PRIVATE_FORMAT_XML);
$RSA->setHash(CRYPT_SHA512);
$RSA->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
return $RSA->sign($data);
}
C#代码:
private String signData(String data) {
byte[] private_key_modulus_array = Convert.FromBase64String(B64_MODULUS);
byte[] private_key_exponent_array = Convert.FromBase64String(B64_EXPONENT);
byte[] private_key_p_array = Convert.FromBase64String(B64_P);
byte[] private_key_q_array = Convert.FromBase64String(B64_Q);
byte[] private_key_dp_array = Convert.FromBase64String(B64_DP);
byte[] private_key_dq_array = Convert.FromBase64String(B64_DQ);
byte[] private_key_inverseQ_array = Convert.FromBase64String(B64_INVERSE_Q);
byte[] private_key_d_array = Convert.FromBase64String(B64_D);
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
//Set RSAKeyInfo to the private key values.
RSAKeyInfo.Modulus = private_key_modulus_array;
RSAKeyInfo.P = private_key_p_array;
RSAKeyInfo.Q = private_key_q_array;
RSAKeyInfo.DP = private_key_dp_array;
RSAKeyInfo.DQ = private_key_dq_array;
RSAKeyInfo.D = private_key_d_array;
RSAKeyInfo.InverseQ = private_key_inverseQ_array;
RSAKeyInfo.Exponent = private_key_exponent_array;
RSA.ImportParameters(RSAKeyInfo);
return Convert.ToBase64String(RSA.SignData(Encoding.ASCII.GetBytes(data), new SHA512CryptoServiceProvider()));
}
使用 C# 生成的签名与 PHP 生成的签名不同。
我在想,也许 phpseclib 没有正确解析私钥??
在 C# 端签名与使用内置加密和 bouncycastle 库创建时相同。
我该怎么办?我是否需要任何其他密钥格式来实现一致性?
感谢您的帮助。
差异是由于在应用 RSA 求幂原语之前数据的不同格式造成的。 RSACryptoServiceProvider SignData 方法使用一种有时称为“原始”签名的格式。 phpseclib rsa 模块改为使用 PKCS#1 version 1.5.
中指定的格式
您应该能够通过在 .NET 端使用 RSAPKCS1SignatureFormatter class 来获得兼容的结果。这是一个小片段来说明:
static byte[] PKCS1Signature(string content, RSACryptoServiceProvider rsaKey) {
byte[] contentBytes = Encoding.UTF8.GetBytes (content);
RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter (rsaKey);
signer.SetHashAlgorithm ("SHA512");
SHA512 hasher = SHA512.Create ();
byte[] hash = hasher.ComputeHash (contentBytes);
byte[] SignedHash = signer.CreateSignature (hash);
return SignedHash;
}
This answer 关于 RSA encryption 的相关问题,而这个问题是关于 RSA signatures.
我在 php 端使用 openssl 并在 C# 端使用 BouncyCastle 解决了这个问题。
关键是 pem 格式。
这是 512 位测试密钥的样子:
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6
zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==
-----END PUBLIC KEY-----
密钥是使用 OpenSSL 实用程序生成的:www.openssl.org
您可以使用以下方法获得 private/public 密钥对:
openssl genrsa 512 >private_key.txt
openssl rsa -pubout <private_key.txt >public_key.txt
512 是密钥位大小。
PHP 数据签名:
function signData($message)
{
$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$binary_signature = "";
openssl_sign($message, $binary_signature, $private_key, OPENSSL_ALGO_SHA1);
return base64_encode($binary_signature);
}
仅使用 public 密钥和 BouncyCastle 的 C# 签名验证:
public bool verifySignature(byte[] signatureBytes, String message)
{
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)new PemReader(newStringReader(PUBLIC_KEY)).ReadObject();
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
sig.Init(false, publicKey);
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
sig.BlockUpdate(messageBytes, 0, messageBytes.Length);
return sig.VerifySignature(signatureBytes);
}
简单明了。我不敢相信我在这上面浪费了几天...
无论如何,谢谢你的帮助。
确保您在签名时使用与验证签名时相同的填充模式,如 。
但是,如果你想要安全,use RSASSA-PSS with e=65537 and MFG1+SHA256 instead of PKCS1v1.5 padding(phpseclib 都支持)。
也可以考虑完全放弃 RSA,转而使用 Ed25519, which is available in PHP 7.2 or from PECL (PHP). On the other end, get libsodium.net (C#)。
在PHP端:
$message = 'Whatever you want';
$signature = sodium_crypto_sign_detached($message, $secretKey);
// ...
if (sodium_crypto_sign_verify_detached($signature, $message, $publicKey)) {
// Valid signature for message and public key
}
C#端:
var message = "whatever you want";
// privateKey is a byte[] of length 64
// publicKey is a byte[] of length 32
// get a signature for the message
var signature = PublicKeyAuth.SignDetached(message, privateKey);
// check the signature for the message
if (PublicKeyAuth.VerifyDetached(signature, message, publicKey))
{
// message ok
}
我正在创建一个许可证密钥生成器,RSA 签署 base64 编码的许可证密钥数据并将签名附加到许可证 data.On 最终用户端签名使用捆绑的 public 密钥进行验证application.We 在 .net 上有应用程序 运行,php、java 和其他 platforms.License 模型应该对所有人都相同。 现在 trouble:I 已经使用内置的加密提供程序在 C# 中创建了 2048 位 public/private 密钥,并以 XML 格式导出密钥以获得 b64 中透明的密钥 BigInteger 组件 encoding.License密钥生成器应该在 php 中工作,我正在使用 phpseclib 导入 XML 密钥并签署 data.Php 代码:
function sign($data)
{
$RSA_PRIVATE_KEY = "<RSAKeyValue>
<Modulus>oPmCaLewqKTkRPpKLHz+9hEbrUbVdKNkIxzm4h5/wmuId6PSx6ntV2T44/NSzfx56LffyXvzx27GYEKk4zffpPYKdRIGReZVqfl2U5K3jcuv0h4657ge0nZ5W9vrYMDSFjgtZOSw8t2opWC8IZVUI3X9W8mp1Z3xqtwREpLC/kV0YE1Kmem8k8B4Tv1+qj5C6oPJjhy+T3JipYOQIyVRUoCdo3EHpDQ6K7twKD+Si/rASHyvoCJZTPvWI1w9y9FD8CxstkY7+ap8J9DMczyiFsE4kJtziBKZFph4ZRqz4kSA0TXj0lXhGEAcn1IDjhV5W37PdsWOkUTxBH7Bm7mpuw==</Modulus>
<Exponent>AQAB</Exponent>
<P>xU8K0Z1Mn0cLOHrwMIujXvtJbXpmjFfyOkm+WkeNV2hjDmdgMibJJvhqPEYPSabEHF4us8H4IeEqeInGK04LrYmbe3IVgmuGdpacR01WISbqXiarsKbcHkR65mfotQmxay/n3Swi8hN9yTanSJyhoHFBiJ0qYM0VNdamu7LDeGk=</P>
<Q>0Nukxy2o/o7z6NeR9g+dUcOQzXfWS2Bu4vAXyHGpJArGcIzl4Z2jNuUztGj5sO5b+9SQs4tgijsjbsEQUNN7R1+PB7Zwc50PvGgEvGaIJkPphGoJMNCw4Q2I8tNPb86cEd4WLJ8E6ad93vX0tyZAnn3LrjPg3Bvvxtq157jZLIM=</Q>
<DP>tGRV0dtsyFrdyV+s5dVlIlvAgFVeGIX3so7leAjfEsEff3XIH1ISqoyIJF8xbvcHaaA6NqLqx57jg50DD2iliJ29B5oATGMeZqHAc/gi/OBlensEkdecfBfD/Y+W1J3uFb+Qz0ehE436fNJ5EwwRQW0Kq2p16lbWQ4jim80OpbE=</DP>
<DQ>vML2bumuhbrvaK6EBa5hEce9dGXtcJyMO2ChLhDDvIZciNZe4YUWQQPvsgr6OFWFHtojmZHLQ8NlJ7EnrNUl4wDThTX29haqZS5hsWC9hk/0mi83dT33zr7r2gLvFW7XETL2OYfS6dXt5ffHH0xcNKIe1qeef3BkSgXbR72B0j8=</DQ>
<InverseQ>TffUf2HXQOmVEUo6rinASIOJOfwfucd+MjwDaK61bISFY5J2n3MYRX4wEiFxXlcYgXnR9CsbwRVhUDIDzLuB+ykAG62LkbqCKUYjzyN3RDbc/MSj/sXSw60pTc4DesVhQlumd0zGUOxsFkjOlUowxwIDENiSVFew1IfAOZiakpk=</InverseQ>
<D>AKHPgpxrXn4nQfi+9HsZKoYurE4sOw+ug6TIE03jWolpjm606SvK+XOKtqUXR3pyUBjzZqsh7eqKxN3+H8DxvogTdRo5BBU/c4dokN4b8maWWNDdkliwEPYoy9Tf5mVbbdLn+rlwfcOjtzfbWpZnhNbLGTfVfuKRNwaI2qB7kNwGB1fd1t4xMLWNozgoxFuiiKFbJKmLEj9zHP/KqjEnOH/zEuUBnXiqGMnCMmD7KnD5WqcqSDOahn0TBFlMxV+9Ul2447bu5LTGWhm3RBPEGgtjMboKC3PlgqwYDpC2gbzX5ZsBNCiuGgumxBHgOfAIOVzI01MZTFEpTcTt3BUrwQ==</D>
</RSAKeyValue>";
$RSA = new Crypt_RSA();
$RSA->loadKey($RSA_PRIVATE_KEY, CRYPT_RSA_PRIVATE_FORMAT_XML);
$RSA->setHash(CRYPT_SHA512);
$RSA->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
return $RSA->sign($data);
}
C#代码:
private String signData(String data) {
byte[] private_key_modulus_array = Convert.FromBase64String(B64_MODULUS);
byte[] private_key_exponent_array = Convert.FromBase64String(B64_EXPONENT);
byte[] private_key_p_array = Convert.FromBase64String(B64_P);
byte[] private_key_q_array = Convert.FromBase64String(B64_Q);
byte[] private_key_dp_array = Convert.FromBase64String(B64_DP);
byte[] private_key_dq_array = Convert.FromBase64String(B64_DQ);
byte[] private_key_inverseQ_array = Convert.FromBase64String(B64_INVERSE_Q);
byte[] private_key_d_array = Convert.FromBase64String(B64_D);
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
//Set RSAKeyInfo to the private key values.
RSAKeyInfo.Modulus = private_key_modulus_array;
RSAKeyInfo.P = private_key_p_array;
RSAKeyInfo.Q = private_key_q_array;
RSAKeyInfo.DP = private_key_dp_array;
RSAKeyInfo.DQ = private_key_dq_array;
RSAKeyInfo.D = private_key_d_array;
RSAKeyInfo.InverseQ = private_key_inverseQ_array;
RSAKeyInfo.Exponent = private_key_exponent_array;
RSA.ImportParameters(RSAKeyInfo);
return Convert.ToBase64String(RSA.SignData(Encoding.ASCII.GetBytes(data), new SHA512CryptoServiceProvider()));
}
使用 C# 生成的签名与 PHP 生成的签名不同。 我在想,也许 phpseclib 没有正确解析私钥??
在 C# 端签名与使用内置加密和 bouncycastle 库创建时相同。
我该怎么办?我是否需要任何其他密钥格式来实现一致性?
感谢您的帮助。
差异是由于在应用 RSA 求幂原语之前数据的不同格式造成的。 RSACryptoServiceProvider SignData 方法使用一种有时称为“原始”签名的格式。 phpseclib rsa 模块改为使用 PKCS#1 version 1.5.
中指定的格式您应该能够通过在 .NET 端使用 RSAPKCS1SignatureFormatter class 来获得兼容的结果。这是一个小片段来说明:
static byte[] PKCS1Signature(string content, RSACryptoServiceProvider rsaKey) {
byte[] contentBytes = Encoding.UTF8.GetBytes (content);
RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter (rsaKey);
signer.SetHashAlgorithm ("SHA512");
SHA512 hasher = SHA512.Create ();
byte[] hash = hasher.ComputeHash (contentBytes);
byte[] SignedHash = signer.CreateSignature (hash);
return SignedHash;
}
This answer 关于 RSA encryption 的相关问题,而这个问题是关于 RSA signatures.
我在 php 端使用 openssl 并在 C# 端使用 BouncyCastle 解决了这个问题。
关键是 pem 格式。
这是 512 位测试密钥的样子:
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6
zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==
-----END PUBLIC KEY-----
密钥是使用 OpenSSL 实用程序生成的:www.openssl.org
您可以使用以下方法获得 private/public 密钥对:
openssl genrsa 512 >private_key.txt
openssl rsa -pubout <private_key.txt >public_key.txt
512 是密钥位大小。
PHP 数据签名:
function signData($message)
{
$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$binary_signature = "";
openssl_sign($message, $binary_signature, $private_key, OPENSSL_ALGO_SHA1);
return base64_encode($binary_signature);
}
仅使用 public 密钥和 BouncyCastle 的 C# 签名验证:
public bool verifySignature(byte[] signatureBytes, String message)
{
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)new PemReader(newStringReader(PUBLIC_KEY)).ReadObject();
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
sig.Init(false, publicKey);
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
sig.BlockUpdate(messageBytes, 0, messageBytes.Length);
return sig.VerifySignature(signatureBytes);
}
简单明了。我不敢相信我在这上面浪费了几天...
无论如何,谢谢你的帮助。
确保您在签名时使用与验证签名时相同的填充模式,如
但是,如果你想要安全,use RSASSA-PSS with e=65537 and MFG1+SHA256 instead of PKCS1v1.5 padding(phpseclib 都支持)。
也可以考虑完全放弃 RSA,转而使用 Ed25519, which is available in PHP 7.2 or from PECL (PHP). On the other end, get libsodium.net (C#)。
在PHP端:
$message = 'Whatever you want';
$signature = sodium_crypto_sign_detached($message, $secretKey);
// ...
if (sodium_crypto_sign_verify_detached($signature, $message, $publicKey)) {
// Valid signature for message and public key
}
C#端:
var message = "whatever you want";
// privateKey is a byte[] of length 64
// publicKey is a byte[] of length 32
// get a signature for the message
var signature = PublicKeyAuth.SignDetached(message, privateKey);
// check the signature for the message
if (PublicKeyAuth.VerifyDetached(signature, message, publicKey))
{
// message ok
}