I'm trying to implement AES 128 OFB encryption / decryption to match the Z-Wave Application Security Layer (S0) implementation. I can test the correct behavior by using a PC Controller application, with the following test data:
External Nonce: C7 16 D1 58 7E D2 9F 18
Internal Nonce: 68 DE E6 4A 88 A4 A3 E8
Security Key: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Decrypted Message: 00 98 06 2D C3 51 38 5D D8 4D 25 F5 ED 3B C5 B5 AA E2 36
Encrypted Message: 50 AE 49 A7 88 6C A9 BF E6 DA 36 A0 EF B8 CF D2 AA E2 C1
Information I have:
- AES-128 OFB. Output Feedback, or OFB, is the mode of operation used to encrypt and decrypt the payload.
- IV = (sender's nonce || receiver's nonce) (the payload is encrypted with the external and internal nonce concatenated together.)
This is my attempt to implement the Z-Wave AES 128 OFB encryption / decryption in C#:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Text;
namespace AesEncryption
{
class Program
{
static void Main(string[] args)
{
byte[] externalNonce = new byte[] { 0xC7, 0x16, 0xD1, 0x58, 0x7E, 0xD2, 0x9F, 0x18 };
byte[] internalNonce = new byte[] { 0x68, 0xDE, 0xE6, 0x4A, 0x88, 0xA4, 0xA3, 0xE8 };
byte[] securityKey = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] unencryptedMessage = new byte[] { 0x00, 0x98, 0x06, 0x2D, 0xC3, 0x51, 0x38, 0x5D, 0xD8, 0x4D, 0x25, 0xF5, 0xED, 0x3B, 0xC5, 0xB5, 0xAA, 0xE2, 0x36 };
byte[] initializationVector = InitializationVector(externalNonce, internalNonce);
var cipher = CipherUtilities.GetCipher("AES/OFB/NoPadding");
var keyParameter = new KeyParameter(securityKey);
ICipherParameters cipherParameters = new ParametersWithIV(keyParameter, initializationVector);
cipher.Init(true, cipherParameters);
var encryptedMessage = cipher.DoFinal(unencryptedMessage);
var encryptedMessageAsHexString = ToHexString(encryptedMessage);
}
static byte[] InitializationVector(byte[] externalNonce, byte[] internalNonce)
{
byte[] iv = new byte[externalNonce.Length + internalNonce.Length];
for (int i = 0; i < externalNonce.Length; i++)
iv[i] = externalNonce[i];
for (int i=0; i< internalNonce.Length; i++)
iv[i + externalNonce.Length] = internalNonce[i];
return iv;
}
public static string ToHexString(byte[] buffer)
{
StringBuilder stringBuilder = new StringBuilder(64);
for (int i = 0; i < buffer.Length; i++)
{
stringBuilder.Append($"{buffer[i]:x2}");
if (i < (buffer.Length - 1))
stringBuilder.Append(' ');
}
return stringBuilder.ToString();
}
}
}
The problem is that my code produces this encrypted result:
"6c 60 2b 6f 53 bb 36 74 3f 1a 50 dc fe db dd c7 d4 84 aa"
while the correct result is:
"50 AE 49 A7 88 6C A9 BF E6 DA 36 A0 EF B8 CF D2 AA E2 C1"
What could I be missing?