AES 加密和 WCF 问题
AES Encryption And WCF Issue
感谢您抽空阅读本期!我在使用 AES 加密时遇到 WCF 服务调用问题。不使用加密时不会出现此问题,我可以毫无问题地在 WCF 外部传递值。 WCF 方法调用非常简单,如下所示:
[WebMethod(Description = "Test")]
[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
UriTemplate = "TestIt?TestVal={TestVal}")]
public string TestIt(string TestVal)
{
return TestVal;
}
如您所见,我所做的只是返回传入的值。当我使用 URL 编码调用此方法时,一切正常 - 这是一个调用和支持方法:
//This works without issue
string testValue = "This is a turkey";
string testResp = baseURL + "TestIt?TestVal=" + UrlEncode(StringToBytes(testValue));
testResp = GetWebContent(testResp);
if (testResp != testValue)
{
Console.WriteLine("Something is wrong ...");
return;
}
public static byte[] StringToBytes(string str)
{
byte[] data = new byte[str.Length * 2];
for (int i = 0; i < str.Length; ++i)
{
char ch = str[i];
data[i * 2] = (byte)(ch & 0xFF);
data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
}
return data;
}
public string UrlEncode(byte[] BytesToEncode)
{
return WebUtility.UrlEncode(StringFromBytes(BytesToEncode));
}
GetWebContent 调用是我使用多年的标准 .NET HttpWebRequest,不属于问题所在。
当我使用完全相同的方法,但使用简单的 AES 加密时,一切都崩溃了。这是代码以及返回值和原始值:
//This bombs completely
string encryptedMessage = rsaMan.UrlEncode(SimpleEncrypt(StringToBytes(baseMessage), newMessageKey, null));
testValue = encryptedMessage;
testResp = baseURL + "TestIt?TestVal=" + testValue;
testResp = GetWebContent(testResp);
if (testResp != testValue)
{
Console.WriteLine("Something is wrong...");
return;
}
//testResp - 穟髐뵙쒒励亰鬾氹잸꿈曬꼰ጾ衢⠾봚媎锽揰玡䓅㼣༦觳땔㋐鹡ഡ渮쬎䊱ᴩᵳ鲇宙衹�辦袊纼돟궁ড屘੩�ၨꖿ뿝ꘊ溇淋₰Ꜭ�蛸컾巍鼘䮈甩処�틵䞾�挅ꄀ敘⧘進䟿闍많㌆圜㦗䅉ꪢ稜퉏븻륿a�㠇盌雗㎠ભ֕熼뭣켡惥擛し钃朕㎌撱淔罈뱷똠恏窴䟭墅왆햺룢殴⫯敒Ԫⶕ΄뮷ꆢ붎뉶莿쎴珦Ⲋ⢗穃欝箈⋄㺢齕쯏덼ナ�立橧ꙸ辫㝧亱藆캮ꊋ䠤ᛸ읅哒ῡꅾ젚펗큩晳ꛚ᷿歺❺鬜ヂ앭냁܇러謗ퟯ㦷䄗Ԏ햦괧쎂Ƅは沩ᰇꩊ쀍☳Ꝓ㪹兞皜鷔䴼엒异꾮찑ᗄ┝딪ಘ遛豲ꖋள꺡뒯恘ﲘ厔⍟랈馅呢꜓�풉ꏼ�绂꙾굯䂶돉⨦凌慺颴멘ใ쉛ᯀ娈Ⰾ墲䢚뉎藍쫳㘡ᠤ싼귦᯽䄃蔐�썃呈鷐竱盽
//testValue - %E7%A9%9F%E9%AB%90%EB%B5%99%EC%92%92%EE%B8%80%E5%8A%B1%E4%BA%B0%E9%AC%BE%E6%B0%B9%EC%9E%B8%EF%9B%B0%EA%BF%88%E6%9B%AC%EA%BC%B0%E1%8C%BE%E8%A1%A2%EE%95%93%E2%A0%BE%EB%B4%9A%E5%AA%8E%E9%94%BD%E6%8F%B0%E7%8E%A1%E4%93%85%E3%BC%A3%E0%BC%A6%E8%A7%B3%EB%95%94%E3%8B%90%E9%B9%A1%E0%B4%A1%E6%B8%AE%EC%AC%8E%E4%8A%B1%E1%B4%A9%E1%B5%B3%E9%B2%87%EF%98%A1%E5%AE%99%E8%A1%B9%EF%BF%BD%E8%BE%A6%E8%A2%8A%E7%BA%BC%EE%B4%9C%EB%8F%9F%EF%88%95%EA%B6%81%E0%A6%A1%E5%B1%98%E0%A9%A9%EF%BF%BD%E1%81%A8%EA%96%BF%EB%BF%9D%EF%A3%AA%EA%98%8A%E6%BA%87%EF%A7%B5%E2%82%B0%EA%9C%AC%EF%BF%BD%E8%9B%B8%EC%BB%BE%E5%B7%8D%E9%BC%98%E4%AE%88%E7%94%A9%E5%87%A6%EF%BF%BD%ED%8B%B5%E4%9E%BE%EF%BF%BD%E6%8C%85%EA%84%80%E6%95%98%EF%92%B2%E1%9D%94%E2%A7%98%E9%80%B2%E4%9F%BF%E9%97%8D%EB%A7%8E%E3%8C%86%E5%9C%9C%E3%A6%97%E4%85%89%EA%AA%A2%E7%A8%9C%EA%9B%BE%ED%89%8F%EB%B8%BB%EB%A5%BFa%EF%BF%BD%E3%A0%87%E7%9B%8C%EF%9A%83%EE%A3%A6%E9%9B%97%EE%A2%A4%E3%8E%A0%E0%AA%AD%EF%8D%8D%D6%95%E7%86%BC%EB%AD%A3%EC%BC%A1%E6%83%A5%E6%93%9B%EE%96%9F%EE%9A%A5%E3%81%97%E9%92%83%E6%9C%95%E3%8E%8C%E6%92%B1%E6%B7%94%E7%BD%88%EE%96%AC%EB%B1%B7%EE%AE%87%EB%98%A0%E6%81%8F%E7%AA%B4%E4%9F%AD%E5%A2%85%EC%99%86%ED%96%BA%EB%A3%A2%E6%AE%B4%E2%AB%AF%E6%95%92%D4%AA%E2%B6%95%CE%84%EB%AE%B7%EA%86%A2%EB%B6%8E%EE%B2%93%EB%89%B6%E8%8E%BF%EC%8E%B4%E7%8F%A6%E2%B2%8A%E2%A2%97%EE%99%9A%E7%A9%83%E6%AC%9D%E7%AE%88%E2%8B%84%E3%BA%A2%E9%BD%95%EC%AF%8F%EB%8D%BC%EF%BE%85%EF%BF%BD%E7%AB%8B%EF%94%B3%E6%A9%A7%EA%99%B8%E8%BE%AB%E3%9D%A7%E4%BA%B1%EE%AC%82%EE%A8%A9%E8%97%86%EC%BA%AE%EA%8A%8B%E4%A0%A4%E1%9B%B8%E0%AB%B3%EC%9D%85%E5%93%92%E1%BF%A1%EA%85%BE%EC%A0%9A%ED%8E%97%ED%81%A9%EA%92%8E%E6%99%B3%EA%9B%9A%E1%B7%BF%E6%AD%BA%E2%9D%BA%E9%AC%9C%E3%83%82%EC%95%AD%EB%83%81%DC%87%EB%9F%AC%E8%AC%97%ED%9F%AF%E3%A6%B7%E4%84%97%D4%8E%ED%96%A6%EA%B4%A7%EE%BB%A9%EE%96%95%EC%8E%82%C6%84%EF%82%88%E3%81%AF%E6%B2%A9%EF%81%83%E1%B0%87%EE%97%81%EA%A9%8A%EC%80%8D%E2%98%B3%EA%9D%92%E3%AA%B9%E5%85%9E%E7%9A%9C%E9%B7%94%E4%B4%BC%EC%97%92%E5%BC%82%EA%BE%AE%EC%B0%91%E1%97%84%E2%94%9D%EB%94%AA%E0%B2%98%E9%81%9B%E8%B1%B2%EA%96%8B%E0%AE%B3%EA%BA%A1%EB%92%AF%E6%81%98%EF%B2%98%E5%8E%94%E2%8D%9F%EB%9E%88%E9%A6%85%E5%91%A2%EA%9C%93%EF%BF%BD%ED%92%89%EA%8F%BC%EF%BF%BD%EF%9B%B0%E7%BB%82%EA%99%BE%EA%B5%AF%E1%A2%AC%E4%82%B6%EB%8F%89%E2%A8%A6%E5%87%8C%E6%85%BA%EE%90%AC%E9%A2%B4%EB%A9%98%E0%B9%83%EC%89%9B%E1%AF%80%E5%A8%88%EE%8E%91%E2%B0%8E%E5%A2%B2%E4%A2%9A%EB%89%8E%EE%BB%9B%EF%A4%A3%EC%AB%B3%E3%98%A1%E1%A0%A4%EC%8B%BC%EA%B7%A6%EE%90%A8%E1%AF%BD%E4%84%83%E8%94%90%EF%BF%BD%EC%8D%83%E5%91%88%E9%B7%90%E7%AB%B1%E7%9B%BD
public static string SimpleEncrypt(string secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncrypt(plainText, key, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}
public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
//User Error Checks
if (key == null || key.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");
if (secretMessage == null || secretMessage.Length == 0)
throw new ArgumentException("Secret Message Required!", "secretMessage");
//Non-secret Payload Optional
nonSecretPayload = nonSecretPayload ?? new byte[] { };
//Using random nonce large enough not to repeat
var nonce = new byte[NonceBitSize / 8];
Random.NextBytes(nonce, 0, nonce.Length);
var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
cipher.Init(true, parameters);
//Generate Cipher Text With Auth Tag
var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
//Assemble Message
using (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
//Prepend Authenticated Payload
binaryWriter.Write(nonSecretPayload);
//Prepend Nonce
binaryWriter.Write(nonce);
//Write Cipher Text
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}
从字面上看,唯一的区别是加密,并且在 WCF 服务调用中看到的值已完全损坏 - 就好像 WCF 以某种方式试图将 URL 编码值转换为 unicode 或其他东西。
很明显我遗漏了一些东西,但我不知道可能是什么 - 有人有任何见解吗?
注意:我还尝试使用 StringFromBytes(下方)代替 Convert.ToBase64String 和 StringToBytes 代替 Convert.FromBase64String,但没有任何区别。
public static string StringFromBytes(byte[] arr)
{
char[] ch = new char[arr.Length / 2];
for (int i = 0; i < ch.Length; ++i)
{
ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
}
return new String(ch);
}
这里似乎从未调用过 "string SimpleEncrypt(string ...)" 方法,但这也许是您所期望的。方法重载可能会造成混淆。你试过了吗:
WebUtility.UrlEncode(SimpleEncrypt(baseMessage, ...))
?
感谢您抽空阅读本期!我在使用 AES 加密时遇到 WCF 服务调用问题。不使用加密时不会出现此问题,我可以毫无问题地在 WCF 外部传递值。 WCF 方法调用非常简单,如下所示:
[WebMethod(Description = "Test")]
[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
UriTemplate = "TestIt?TestVal={TestVal}")]
public string TestIt(string TestVal)
{
return TestVal;
}
如您所见,我所做的只是返回传入的值。当我使用 URL 编码调用此方法时,一切正常 - 这是一个调用和支持方法:
//This works without issue
string testValue = "This is a turkey";
string testResp = baseURL + "TestIt?TestVal=" + UrlEncode(StringToBytes(testValue));
testResp = GetWebContent(testResp);
if (testResp != testValue)
{
Console.WriteLine("Something is wrong ...");
return;
}
public static byte[] StringToBytes(string str)
{
byte[] data = new byte[str.Length * 2];
for (int i = 0; i < str.Length; ++i)
{
char ch = str[i];
data[i * 2] = (byte)(ch & 0xFF);
data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
}
return data;
}
public string UrlEncode(byte[] BytesToEncode)
{
return WebUtility.UrlEncode(StringFromBytes(BytesToEncode));
}
GetWebContent 调用是我使用多年的标准 .NET HttpWebRequest,不属于问题所在。
当我使用完全相同的方法,但使用简单的 AES 加密时,一切都崩溃了。这是代码以及返回值和原始值:
//This bombs completely
string encryptedMessage = rsaMan.UrlEncode(SimpleEncrypt(StringToBytes(baseMessage), newMessageKey, null));
testValue = encryptedMessage;
testResp = baseURL + "TestIt?TestVal=" + testValue;
testResp = GetWebContent(testResp);
if (testResp != testValue)
{
Console.WriteLine("Something is wrong...");
return;
}
//testResp - 穟髐뵙쒒励亰鬾氹잸꿈曬꼰ጾ衢⠾봚媎锽揰玡䓅㼣༦觳땔㋐鹡ഡ渮쬎䊱ᴩᵳ鲇宙衹�辦袊纼돟궁ড屘੩�ၨꖿ뿝ꘊ溇淋₰Ꜭ�蛸컾巍鼘䮈甩処�틵䞾�挅ꄀ敘⧘進䟿闍많㌆圜㦗䅉ꪢ稜퉏븻륿a�㠇盌雗㎠ભ֕熼뭣켡惥擛し钃朕㎌撱淔罈뱷똠恏窴䟭墅왆햺룢殴⫯敒Ԫⶕ΄뮷ꆢ붎뉶莿쎴珦Ⲋ⢗穃欝箈⋄㺢齕쯏덼ナ�立橧ꙸ辫㝧亱藆캮ꊋ䠤ᛸ읅哒ῡꅾ젚펗큩晳ꛚ᷿歺❺鬜ヂ앭냁܇러謗ퟯ㦷䄗Ԏ햦괧쎂Ƅは沩ᰇꩊ쀍☳Ꝓ㪹兞皜鷔䴼엒异꾮찑ᗄ┝딪ಘ遛豲ꖋள꺡뒯恘ﲘ厔⍟랈馅呢꜓�풉ꏼ�绂꙾굯䂶돉⨦凌慺颴멘ใ쉛ᯀ娈Ⰾ墲䢚뉎藍쫳㘡ᠤ싼귦᯽䄃蔐�썃呈鷐竱盽
//testValue - %E7%A9%9F%E9%AB%90%EB%B5%99%EC%92%92%EE%B8%80%E5%8A%B1%E4%BA%B0%E9%AC%BE%E6%B0%B9%EC%9E%B8%EF%9B%B0%EA%BF%88%E6%9B%AC%EA%BC%B0%E1%8C%BE%E8%A1%A2%EE%95%93%E2%A0%BE%EB%B4%9A%E5%AA%8E%E9%94%BD%E6%8F%B0%E7%8E%A1%E4%93%85%E3%BC%A3%E0%BC%A6%E8%A7%B3%EB%95%94%E3%8B%90%E9%B9%A1%E0%B4%A1%E6%B8%AE%EC%AC%8E%E4%8A%B1%E1%B4%A9%E1%B5%B3%E9%B2%87%EF%98%A1%E5%AE%99%E8%A1%B9%EF%BF%BD%E8%BE%A6%E8%A2%8A%E7%BA%BC%EE%B4%9C%EB%8F%9F%EF%88%95%EA%B6%81%E0%A6%A1%E5%B1%98%E0%A9%A9%EF%BF%BD%E1%81%A8%EA%96%BF%EB%BF%9D%EF%A3%AA%EA%98%8A%E6%BA%87%EF%A7%B5%E2%82%B0%EA%9C%AC%EF%BF%BD%E8%9B%B8%EC%BB%BE%E5%B7%8D%E9%BC%98%E4%AE%88%E7%94%A9%E5%87%A6%EF%BF%BD%ED%8B%B5%E4%9E%BE%EF%BF%BD%E6%8C%85%EA%84%80%E6%95%98%EF%92%B2%E1%9D%94%E2%A7%98%E9%80%B2%E4%9F%BF%E9%97%8D%EB%A7%8E%E3%8C%86%E5%9C%9C%E3%A6%97%E4%85%89%EA%AA%A2%E7%A8%9C%EA%9B%BE%ED%89%8F%EB%B8%BB%EB%A5%BFa%EF%BF%BD%E3%A0%87%E7%9B%8C%EF%9A%83%EE%A3%A6%E9%9B%97%EE%A2%A4%E3%8E%A0%E0%AA%AD%EF%8D%8D%D6%95%E7%86%BC%EB%AD%A3%EC%BC%A1%E6%83%A5%E6%93%9B%EE%96%9F%EE%9A%A5%E3%81%97%E9%92%83%E6%9C%95%E3%8E%8C%E6%92%B1%E6%B7%94%E7%BD%88%EE%96%AC%EB%B1%B7%EE%AE%87%EB%98%A0%E6%81%8F%E7%AA%B4%E4%9F%AD%E5%A2%85%EC%99%86%ED%96%BA%EB%A3%A2%E6%AE%B4%E2%AB%AF%E6%95%92%D4%AA%E2%B6%95%CE%84%EB%AE%B7%EA%86%A2%EB%B6%8E%EE%B2%93%EB%89%B6%E8%8E%BF%EC%8E%B4%E7%8F%A6%E2%B2%8A%E2%A2%97%EE%99%9A%E7%A9%83%E6%AC%9D%E7%AE%88%E2%8B%84%E3%BA%A2%E9%BD%95%EC%AF%8F%EB%8D%BC%EF%BE%85%EF%BF%BD%E7%AB%8B%EF%94%B3%E6%A9%A7%EA%99%B8%E8%BE%AB%E3%9D%A7%E4%BA%B1%EE%AC%82%EE%A8%A9%E8%97%86%EC%BA%AE%EA%8A%8B%E4%A0%A4%E1%9B%B8%E0%AB%B3%EC%9D%85%E5%93%92%E1%BF%A1%EA%85%BE%EC%A0%9A%ED%8E%97%ED%81%A9%EA%92%8E%E6%99%B3%EA%9B%9A%E1%B7%BF%E6%AD%BA%E2%9D%BA%E9%AC%9C%E3%83%82%EC%95%AD%EB%83%81%DC%87%EB%9F%AC%E8%AC%97%ED%9F%AF%E3%A6%B7%E4%84%97%D4%8E%ED%96%A6%EA%B4%A7%EE%BB%A9%EE%96%95%EC%8E%82%C6%84%EF%82%88%E3%81%AF%E6%B2%A9%EF%81%83%E1%B0%87%EE%97%81%EA%A9%8A%EC%80%8D%E2%98%B3%EA%9D%92%E3%AA%B9%E5%85%9E%E7%9A%9C%E9%B7%94%E4%B4%BC%EC%97%92%E5%BC%82%EA%BE%AE%EC%B0%91%E1%97%84%E2%94%9D%EB%94%AA%E0%B2%98%E9%81%9B%E8%B1%B2%EA%96%8B%E0%AE%B3%EA%BA%A1%EB%92%AF%E6%81%98%EF%B2%98%E5%8E%94%E2%8D%9F%EB%9E%88%E9%A6%85%E5%91%A2%EA%9C%93%EF%BF%BD%ED%92%89%EA%8F%BC%EF%BF%BD%EF%9B%B0%E7%BB%82%EA%99%BE%EA%B5%AF%E1%A2%AC%E4%82%B6%EB%8F%89%E2%A8%A6%E5%87%8C%E6%85%BA%EE%90%AC%E9%A2%B4%EB%A9%98%E0%B9%83%EC%89%9B%E1%AF%80%E5%A8%88%EE%8E%91%E2%B0%8E%E5%A2%B2%E4%A2%9A%EB%89%8E%EE%BB%9B%EF%A4%A3%EC%AB%B3%E3%98%A1%E1%A0%A4%EC%8B%BC%EA%B7%A6%EE%90%A8%E1%AF%BD%E4%84%83%E8%94%90%EF%BF%BD%EC%8D%83%E5%91%88%E9%B7%90%E7%AB%B1%E7%9B%BD
public static string SimpleEncrypt(string secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncrypt(plainText, key, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}
public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
//User Error Checks
if (key == null || key.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");
if (secretMessage == null || secretMessage.Length == 0)
throw new ArgumentException("Secret Message Required!", "secretMessage");
//Non-secret Payload Optional
nonSecretPayload = nonSecretPayload ?? new byte[] { };
//Using random nonce large enough not to repeat
var nonce = new byte[NonceBitSize / 8];
Random.NextBytes(nonce, 0, nonce.Length);
var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
cipher.Init(true, parameters);
//Generate Cipher Text With Auth Tag
var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
//Assemble Message
using (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
//Prepend Authenticated Payload
binaryWriter.Write(nonSecretPayload);
//Prepend Nonce
binaryWriter.Write(nonce);
//Write Cipher Text
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}
从字面上看,唯一的区别是加密,并且在 WCF 服务调用中看到的值已完全损坏 - 就好像 WCF 以某种方式试图将 URL 编码值转换为 unicode 或其他东西。
很明显我遗漏了一些东西,但我不知道可能是什么 - 有人有任何见解吗?
注意:我还尝试使用 StringFromBytes(下方)代替 Convert.ToBase64String 和 StringToBytes 代替 Convert.FromBase64String,但没有任何区别。
public static string StringFromBytes(byte[] arr)
{
char[] ch = new char[arr.Length / 2];
for (int i = 0; i < ch.Length; ++i)
{
ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
}
return new String(ch);
}
这里似乎从未调用过 "string SimpleEncrypt(string ...)" 方法,但这也许是您所期望的。方法重载可能会造成混淆。你试过了吗:
WebUtility.UrlEncode(SimpleEncrypt(baseMessage, ...))
?