2016-04-16 10 views
0

У меня возникли проблемы с открытием Nacl SecretBox (сгенерированным в java с использованием библиотеки TweetNaclFast) на C# с использованием библиотеки libsodium-net. Я также не могу сделать это наоборот (откройте сборку libsodium-net с помощью TweetNaclFast).Невозможно открыть «SecretBox», сгенерированный TweetNacl (Java) с помощью «Libsodium-net» (C#)

В следующем примере я создам SecretBox с помощью TweetNaclFast (Java) и попытаться открыть его с libsodium-нетто (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) 

Любая идея о том, что я могу делать неправильно?


EDIT

Я думаю, что проблема с одной из библиотек (libsodium-сеть, скорее всего). Если я создать SecretBox с теми же переменными я получаю другую коробку ...

Создание Secret Box с 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 =

ответ

1

Sodium.SecretBox.Create использует оригинальный API NaCl crypto_box(), который требует дополнительного заполнения перед сообщением и зашифрованным текстом.

Этот API немного запутанный и редко используется, за исключением C. Даже в C, люди, использующие его, заканчивают тем, что пишут обертки, чтобы добавить или избавиться от прокладки.

Конструкции box и secretbox, представленные большинством API, не требуют дополнительного заполнения. Зашифрованный текст возвращается непосредственно без 16 дополнительных байтов. Сообщение может быть напрямую передано без добавления 16 nul байтов.

TweetNaclFast не требует каких-либо отступов, но, по-видимому, libsodium-net делает.

Дополнительные 16 байт до зашифрованного текста, которые вы наблюдаете с помощью библиотеки libsodium-net, не содержат никакой полезной информации. Это всего лишь куча нулей. Вы можете безопасно их разбить и добавить позже, когда звоните Sodium.SecretBox.Open.

Обратите внимание, что в отличие от Sodium.SecretBox, Sodium.PublicKeyBox не требует заполнения.

+0

Это именно то, что я нашел. Спасибо за объяснение :) – loveMeansNothing

+1

Это на самом деле [несогласованность в libsodium-net] (https://github.com/adamcaudill/libsodium-net/issues/133). Совместимые функции [были добавлены] (https://github.com/bitbeans/libsodium-net/commit/0d718a4c4d2d1f148a081864496fff7620245956). –

+0

Вы рок @ Френк Денис – loveMeansNothing

0

я должен был прочитать документацию (RTFM) ... Видимо libsodium-сеть добавляет тег аутентификации 16byte на старте шифротекста (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); 
} 

Оно должно теперь верните Привет, переполнение стека!