1

我在使用 libsodium-net 库在 C# 中打开 Nacl SecretBox(使用 TweetNaclFast 库在 java 中生成)时遇到问题。我也不能反过来(使用 TweetNaclFast 打开一个 libsodium-net 生成的框)。

在下面的示例中,我将使用 TweetNaclFast (Java) 创建一个 SecretBox,并尝试使用 libsodium-net (C#) 打开它

创建 SecretBox (Java)

    String secretMessage = "Hello Stack overflow!";
    byte[] messageBytes = secretMessage.getBytes("UTF-8");
    byte[] keyBytes = secureRandomGenerator(); //returns 32 random bytes (256 bits)
    byte[] nonceBytes = TweetNaclFast.makeSecretBoxNonce();

    byte[] boxBytes = new TweetNaclFast.SecretBox(keyBytes).box(messageBytes,nonceBytes);

    System.out.println("Base64 box -> "+Base64.encodeBase64String(boxBytes));
    System.out.println("Base64 key -> "+Base64.encodeBase64String(keyBytes));
    System.out.println("Base64 nonce -> "+Base64.encodeBase64String(nonceBytes));

创建输出

Base64 box -> iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==
Base64 key -> FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=
Base64 nonce -> 2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV

打开 SecretBox (C#)

string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";


        try
        {
            byte[] message = Sodium.SecretBox.Open(
            Convert.FromBase64String(box),
            Convert.FromBase64String(nonce),
            Convert.FromBase64String(key));

            Console.WriteLine(Encoding.UTF8.GetString(message));
        }
        catch (CryptographicException e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
        }

打开输出

Failed to open SecretBox
   at Sodium.SecretBox.Open(Byte[] cipherText, Byte[] nonce, Byte[] key)

关于我可能做错了什么的任何想法?


编辑

我想问题出在其中一个库(最有可能是 libsodium-net)上。如果我用相同的变量创建一个 SecretBox,我会得到一个不同的盒子......

使用 TweetNaclFast 创建一个秘密盒子

String message = "Hello Stack overflow!";
String key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
String nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";

SecretBox box = new SecretBox(Base64.decodeBase64(key));
byte[] cipherText = box.box(message.getBytes("UTF-8"), Base64.decodeBase64(nonce));

返回:yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==

使用 libsodium-net 创建一个秘密盒子

string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";

byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message), 
                                             Convert.FromBase64String(nonce), 
                                             Convert.FromBase64String(key));

Console.WriteLine(Convert.ToBase64String(box));

返回:AAAAAAAAAAAAAAAAAAAAAMgwrf5DixVFj2aVd3XlTVGWh9GRy1Zo/Tb5vEJW1Sj3tWvyDQ8=

4

2 回答 2

3

Sodium.SecretBox.Create使用原始的 NaCl crypto_box()API,它需要在消息和密文之前进行额外的填充。

这个 API 有点混乱,除了在 C 中很少有用。即使在 C 中,使用它的人最终也会编写包装器来添加或去掉填充。

大多数 API 公开的boxandsecretbox结构不需要额外的填充。密文直接返回,之前没有额外的 16 个字节。消息可以直接给出,无需预先添加 16 个 nul 字节。

TweetNaclFast 不需要任何填充,但 libsodium-net 显然需要。

您使用 libsodium-net 观察的密文之前的额外 16 个字节不包含任何有用的信息。这只是一堆零。您可以安全地剥离它们,并在稍后调用时添加它们Sodium.SecretBox.Open

请注意,不像Sodium.SecretBox,Sodium.PublicKeyBox不需要填充。

于 2016-04-16T23:51:42.837 回答
0

我应该阅读文档(RTFM)...显然 libsodium-net 在密文的开头添加了一个 16 字节的身份验证标签(https://bitbeans.gitbooks.io/libsodium-net/content/secret-key_cryptography/authenticated_encryption。 html ). 如果我删除前 16 个字节,我会得到与 TweetNaclFast SecretBox 相同的输出。

string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";

byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message), 
                                             Convert.FromBase64String(nonce), 
                                             Convert.FromBase64String(key));

byte[] boxWithoutAuthenticationTag = new byte[box.Length - 16];
Array.Copy(box, 16, boxWithoutAuthenticationTag, 0, box.Length - 16);
Console.WriteLine(Convert.ToBase64String(boxWithoutAuthenticationTag));

现在返回:yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==


要打开(解密)第一个示例的秘密框,请使用以下代码:

string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";

try
{
    //Libsodium-net SecretBox.Open() requires a 16 byte authentication tag at the start of the ciphertext
    //TweetNaclFast boxing method does not append a 16 byte authentication tag anywhere
    //Thus, we need to add a 16 byte authentication tag at the start of ciphertext encripted by TweetNaclFast
    byte[] authenticationTag = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //Zeroed 16 Bytes Authentication Tag
    byte[] tweetNaclFastCiphertextBytes = Convert.FromBase64String(box);
    byte[] libsodiumNetLikeCiphertext = new byte[tweetNaclFastCiphertextBytes.Length + authenticationTag.Length];
    Array.Copy(authenticationTag, libsodiumNetLikeCiphertext, authenticationTag.Length);
    Array.Copy(tweetNaclFastCiphertextBytes, 0, libsodiumNetLikeCiphertext, authenticationTag.Length, tweetNaclFastCiphertextBytes.Length);
    byte[] nonceBytes = Convert.FromBase64String(nonce);
    byte[] keyBytes = Convert.FromBase64String(key);

    Console.WriteLine(Encoding.UTF8.GetString(Sodium.SecretBox.Open(libsodiumNetLikeCiphertext, nonceBytes, keyBytes)));
}
catch (CryptographicException e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine(e.StackTrace);
}

它现在应该返回Hello Stack 溢出!

于 2016-04-16T22:53:17.683 回答