如何在C#中使用AES-128-GCM解密HEX字符串



我正试图从Kamstrup电表中检索数据,并将其传递给家庭助理。我正在从能量表中获取数据,但它是加密的。根据文件,它被加密如下:使用AES-GCM-128和密钥传输AES-128密钥封装的数据传输(DLMS/COSEM套件0)";

我收到了HEX格式的加密密钥和身份验证密钥。但不知道如何使用它。他们只在Python中提供了一个非常简短的例子,但我离将其翻译成C#还有很长的路要走。

Microsoft有一个使用AES:AES解密的示例我曾试图在此基础上对数据进行解密,但它不起作用。我只得到一根奇怪的绳子,像";(o\u001a)™\0:³\u0081)Ù7ÉS\u001bj\u0004OÍÜœ\u007f¨…"(缩写,但长度约为480个字符)。

作为密钥和IV,我传递来自认证密钥和加密密钥的字节。不确定这有多正确。

Kamstrup提供了一个样本,其中使用认证密钥:";AFB3F93E7204EDB3C27F96DBD51AE0";以及加密密钥";5AD84121D9D20B364B7A11F3C1B5827F";解密以下文本:

DB 08 4B 41 4D 45 01 A4 DC 52 82 01 D0 30 00 07 88 E1 A0 39 B2 D1 4C 71 2D D4 D8 C8 44 0D 53 68 E4 33 BD 70 B7 36 81 E9 A9 EF FE 38 F1 75 A3 7D E9 CD E6 4E 8F 78 0D 8F 18 B4 3F C0 59 D8 79 02 F3 D7 47 B8 14 BC D0 6A 47 00 68 78 01 BD 5D 06 61 20 54 50 7D 44 E7 66 98 CC 3E 35 CC 9D E6 2C 28 4C 0D EE A6 35 B9 BF C5 6C E1 FE 5A 3A 1E 5E 27 0B 0C 18 1A CF 02 15 1F CC 59 21 34 D0 4F 0292 B5 A3 53 38 D7 B7 81 BB 1F 2A 7E 40 71 81 5C EE D4 BA C6 EF AA AF f 79 EF 96 9D 0D B4 6F 51 E0 FC 00 AD 10 5F BE F9 5F C5 F8 85 46 0B 56 32 55 4A C0 5D e B4 F6 5F F2 23 97 2A 47 CF D4 34 B5 F5 E2 D8 53 EA 4C 14 72 86 F0 E2 1C e e 25 26 8C B4 DC 7 e C5 B1 0 f 84 83 C0 10 C8 E6 88 DF 86 58 4D 7C 29 D8 17 31 A4 E0 96 91 41 B6 AD D9 42 E4 0A 96 E3 E2 DC 2F 90 20 BF 9D 58 02 A1 8D C985 BB 54 22 F4 70 C0 62 9D 22 DB 6 f 16 B6 64 7 d B3 C9 F7 27 C1 70 C2 DB 4C 9 a 23 0 f 82 83 46 E8 f 56 D3 47 B6 f e 28 A5 07 AE 21 9A CC 63 AD 5 e 0 6 e CB 94 9D C4 FD C2 D2 F8 08 7A 4A 4C 67 7C 93 C4 C8 90 9D 73 36 D8 B8 B3 79 18 36 C5 55 5E 74 E2 54 82 A4 5F 6 d 8 CE 84 50 47 8F 8 b c 5 d 66 C2 CF 8 b D1 90 D4 87 4E 70 f 5 d 4 CD e 9 9 9 35 5A 81 39 C3 E4 1C D5 F0 88 99 B6 e 9B5 9F C6 03 72 E4 F9 2B C9 98 26 B8 C1 47 F2 09 5F B3 8A 89 14 09 AA 81 E2 27 07 6C 21 CB 7C AF 73 B3 E8 A4 E2 56 C7 0D 95 47 A9 14 F3 9C 16 93 76 BF 92 2B 08 06 4E C4 FB 31 D4 e CD 72 1D 1A 15 1E 4E 68 4F 0B 26 85 C4 B6 9D 96 F5 FB 52 D0 B8 12 79

并获取

0f000000000c07e40107020e2f14f80000002410a0e4b616d73747275705f563030303109060101010800f06000d394c09060101020800ff060000000009060101030800ff060000452c090601101040800ff0600000009060101000001f0601a4dc5209060101010700ff060000009060101020700ff060000000000900101030700ff0600000000900101040700ff060000000900001010000ff090c07e4010 7020e2f80000009060101200700ff1200e09060101340700ff1200df09060101480700ff1200DF090601011f0700f060000000009060101330700ff060000000009061011470700ff0600000009060101150700ff060000009060101290700ff0601000000090601013d0700f06000000009060101210700ff12006409060101350700ff1200640 9060101490700ff120064000000000090601010d0700f12006409060101160700ff06000000000 90601012a0700f6060000000090601013e00700ff060000000 9060101160800ff0600000000009001012a0800f0600000000090601013e00800ff060000000009060101150800ff06000468a09060101290800ff060004678c090601013d0800f060004691b

然后他们建议使用";GuruX DLMS翻译器";以从解密的字符串中获得XML数据。

当谈到加密/解密时,我真的是个新手,所以我真的不确定我在解密中做错了什么。乍一看,它在我看来是输出中的错误编码。但我不知道在哪里更改编码。我花了好几个小时,现在几乎一无所获。

我也尝试过不同的解密工具;scadacore.com";只是想了解一下这个过程。但我也无法做到这一点。

到目前为止用于解密的代码。

static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.BlockSize = 128;
aesAlg.Padding = PaddingMode.None;
//aesAlg.Mode = CipherMode.

// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
csDecrypt.Write(cipherText, 0, cipherText.Length);
//using (StreamReader srDecrypt = new StreamReader(csDecrypt))
//{
//    // Read the decrypted bytes from the decrypting stream
//    // and place them in a string.
//    plaintext = srDecrypt.ReadToEnd();
//}
}
plaintext = System.Text.Encoding.Default.GetString(msDecrypt.ToArray());
var plainTextLength = plaintext.Length;
}
}
return plaintext;
}

你们谁能给我指个正确的方向吗?如有任何帮助,我们将不胜感激。我哪儿也不快。

谢谢!

编辑似乎缺少有关安全标签和nonce的som信息。以下是关于如何将字符串组合在一起的文档。

标签:1字节-系统标题:len+8字节-长度:x字节-安全标头:1或5字节-密码文本:y字节-身份验证标签:12字节

尝试1:

以下两次尝试均失败。第一个失败了:;计算的身份验证标记与输入身份验证标记不匹配"BouncyCastle解决方案失败:;GCM中的mac检查失败";。

我得到了一些帮助来启动和运行Python示例,它完全根据文档解密数据。我已经用C#中的值检查了Python代码中的所有值。一切都一样。这似乎是auth标记带来的问题,但在Python和C#中都是一样的,所以我认为这与C#代码有关。失败于:";aesGcm.Decrypt(nonce,cipherBytes,authTag,plainBytes)">

namespace AesGcmNetCoreTestApp
{
internal class Program
{
static void Main(string[] args)
{
try
{
var cipherText = @"DB 08 4B 41 4D 45 01 A4 DC 52 82 01 D0 30 00 07 88 E1 A0 39 B2 D1 4C 71 2D D4 D8 C8 44 0D 53 68 E4 33 BD 70 B7 36 81 E9 A9 EF FE 38 F1 75 A3 7D E9 CD E6 4E 8F 78 0D 8F 18 B4 3F C0 59 D8 79 02 F3 D7 47 B8 14 BC D0 6A 47 00 68 78 01 BD 5D 06 61 20 54 50 7D 44 E7 66 98 CC 3E 35 CC 9D E6 2C 28 4C 0D EE A6 35 B9 BF C5 6C E1 FE 5A 3A 1E 5E 27 0B 0C 18 1A CF 02 15 1F CC 59 21 34 D0 4F 02 92 B5 A3 53 38 D7 B7 81 BB 1F 2A 7E 40 71 81 5C EE D5 D4 BA C6 EF AA AF F9 79 EF 96 9D 0D B4 6F 51 E5 E0 FC 00 F5 AD 10 5F BE F9 5F C5 F8 85 46 0B 56 32 55 4A C0 5D 9E B4 F6 5F F2 23 97 2A 47 CF D4 34 B5 F5 E2 D8 53 EA 4C 14 72 75 86 F0 E2 1C 6E E1 25 26 8C B4 DC 7E C5 B1 0F 84 83 C0 10 C8 E6 88 DF 86 58 4D 7C 29 D8 17 31 A4 E0 96 91 41 B6 AD D9 42 E4 0A 96 E3 E2 DC 2F 90 20 BF 9D 58 02 A1 8D C9 85 BB 54 22 F4 70 C0 62 9D 22 DB 6F 16 B6 64 7D B3 C9 F7 27 C1 70 C2 DB 4C 9A 23 0F 82 83 46 E8 6F 56 D3 47 B6 2B FE 28 A5 07 AE 2A 21 9A CC 63 AD 5E E0 6E CB 94 9D C4 FD C2 D2 F8 08 02 7A 4A 4C 67 7C 93 C4 C8 90 9D 73 36 D8 B8 B3 79 18 36 C5 55 5E 74 E2 54 82 A4 4A 5F 6D 35 8D CE 84 50 47 8F 8B 2C 5D 56 66 C2 CF 8B D1 90 D4 87 4E 70 7F 5D 4B CD E9 4E 91 35 5A 81 39 C3 E4 1C D5 F0 88 99 B6 5E E9 B5 9F C6 03 72 E4 F9 2B C9 98 26 B8 C1 47 F2 09 5F B3 8A 89 14 09 AA 81 E2 27 07 6C 21 CB 7C AF 73 B3 E8 A4 E2 56 C7 0D 95 47 A9 14 F3 9C 16 93 76 BF 92 2B 08 06 4E C4 FB 31 D4 4E CD 72 1D 1A 15 1E 4E 68 4F 0B 26 85 C4 B6 9D 96 F5 FB 52 D0 B8 12 79";
cipherText = cipherText.Replace(" ", "");
var cipherTextBytes = ConvertHexStringToByteArray(cipherText);
var encryptionKey = "5AD84121D9D20B364B7A11F3C1B5827F";
var encryptionKeyBytes = ConvertHexStringToByteArray(encryptionKey);
var authenticationKey = "AFB3F93E3E7204EDB3C27F96DBD51AE0";
var authenticationKeyBytes = ConvertHexStringToByteArray(authenticationKey);
var peek = ConvertByteArrayToString(encryptionKeyBytes);
var systemTitle = cipherTextBytes.SelectIndexRange(2, 10);
var initializationVector = systemTitle.MergeWith(cipherTextBytes.SelectIndexRange(14, 18));
var additionalAuthenticatedData = cipherTextBytes.SelectIndexRange(13, 14).MergeWith(authenticationKeyBytes);
var authenticationTag = cipherTextBytes.SelectIndexRange(cipherTextBytes.Length - 12, cipherTextBytes.Length);
var res = DecryptGcm(cipherTextBytes, encryptionKeyBytes, authenticationTag, initializationVector);
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}

static byte[] DecryptGcm(byte[] cipherBytes, byte[] encKey, byte[] authTag, byte[] nonce)
{
byte[] plainBytes = new byte[cipherBytes.Length];
using (AesGcm aesGcm = new AesGcm(encKey))
{
aesGcm.Decrypt(nonce, cipherBytes, authTag, plainBytes);
}
return plainBytes;
}
public static string ConvertByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
public static byte[] ConvertHexStringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}

}
public static class ExtensionMethods
{
public static byte[] SelectIndexRange(this byte[] bytes, int from, int to)
{
if (bytes == null) throw new ArgumentNullException("Bytes array cannot be empty.");
if (bytes.Length == 0) throw new ArgumentException("Bytes array cannot be empty.");
if (bytes.Length < from) throw new ArgumentException("From index cannot be lower than length!");
if (bytes.Length < to) throw new ArgumentException("To index cannot be higher than length.");
var res = bytes.Skip(from).Take(to - from).ToArray();
return res;
}
public static byte[] MergeWith(this byte[] origByte, byte[] mergeWithBytes)
{
if (origByte.Length == 0 && mergeWithBytes.Length == 0) return Array.Empty<byte>();
var totalLength = origByte.Length + mergeWithBytes.Length;
var resBytes = new byte[totalLength];
for (int i = 0; i < origByte.Length; i++)
{
resBytes[i] = origByte[i];
}
for (int i = 0; i < mergeWithBytes.Length; i++)
{
var index = i + origByte.Length;
resBytes[index] = mergeWithBytes[i];
}
return resBytes;
}
}
}

我还尝试了使用相同输入的BouncyCastle。失败于:";密码DoFinal(明文字节,偏移量)">

private static string DecryptWithBouncyCastle(byte[] ciphertext, byte[] nonce, byte[] tag, byte[] key)
{
var plaintextBytes = new byte[ciphertext.Length];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), tag.Length * 8, nonce);
cipher.Init(false, parameters);
var bcCiphertext = ciphertext.Concat(tag).ToArray();
var offset = cipher.ProcessBytes(bcCiphertext, 0, bcCiphertext.Length, plaintextBytes, 0);
cipher.DoFinal(plaintextBytes, offset);
return Encoding.UTF8.GetString(plaintextBytes);
}

没有足够的信息,但我确信您使用了错误的API。对于AES-GCM,您应该使用AesGcm类,如下所示:

static byte[] Decrypt(byte[] cipherBytes, byte[] encKey, byte[] authTag, byte[] nonce)
{
byte[] plainBytes = new byte[cipherBytes.Length];
using (AesGcm aesGcm = new AesGcm(encKey))
{
aesGcm.Decrypt(nonce, cipherBytes, authTag, plainBytes);
}
return plainBytes;
}

您没有提供nonce和身份验证标签,所以我无法用您的样本数据进行测试。

相关内容

  • 没有找到相关文章

最新更新