.NET中字符串的简单混淆?

20

我需要通过互联网发送一个大约30个字符的字符串,这个字符串最终可能会成为另一家公司数据库中的ID。

虽然这个字符串本身不会被识别,但我希望它在任何情况下都不可辨认。

在.NET中,最简单的方法是什么,可以使这样的字符串混淆,以便在必要时轻松地恢复?


如果它可以轻易地被反转,那还有什么意义呢? - Bali C
3
当你知道方法时,这应该很容易被逆转。 - Adam Houldsworth
@BaliC:我只是想防止人们检查数据库并直接查看数据。 - Paul Lassiter
由于您正在通过互联网发送字符串,我假设您是通过Web服务进行的?例如,仅使用WCF服务之间的安全通信是否足够? - Jens H
2
我会在这里做一个ROT13转换,这是一个很好的例子:https://dev59.com/fnbZa4cB1Zd3GeqPI7Zh#18739120 - Kram
显示剩余3条评论
4个回答

30
这不是加密

请勿将此答案用于任何需要保密的信息。

它会使字符串对人类来说难以阅读。

它可以往返转换,但如果您的字符串不是“普通”的,并且使用了较大的偏移值,则可能无法转换回原始状态。

这段代码无法防止有组织的破解尝试。一个聪明而有技巧的人可以用纸和笔解码它。

以下是原始答案。

如何尝试一些古典风格的东西(带有现代的变化)?

public static string Caesar(this string source, Int16 shift)
{
    var maxChar = Convert.ToInt32(char.MaxValue);
    var minChar = Convert.ToInt32(char.MinValue);

    var buffer = source.ToCharArray();

    for (var i = 0; i < buffer.Length; i++)
    {
        var shifted = Convert.ToInt32(buffer[i]) + shift;

        if (shifted > maxChar)
        {
            shifted -= maxChar;
        }
        else if (shifted < minChar)
        {
            shifted += maxChar;
        }

        buffer[i] = Convert.ToChar(shifted);
    }

    return new string(buffer);
}

显然你会这样使用

var plain = "Wibble";
var caesered = plain.Caesar(42);
var newPlain = caesered.Caesar(-42);

它很快,你的密钥只是一个Int16,并且可以防止普通观察者复制粘贴该值,但它并不安全。

我喜欢这个 :) 假设我把这个字符串存储在HTML页面中,我想通过JavaScript解密并使用该字符串,你能向我展示如何操作吗? - Martin Sansone - MiOEE
1
@TheDonSansone,这可能有点棘手。虽然我可以编写一个JavaScript等效的函数,但是shift和Unicode的某些组合可能会产生不映射到实际Unicode代码点的char值。如果数据在两个.NET组件之间以二进制形式传输,则没有问题,但是当通过HTTP返回给未知浏览器时,我无法确定会发生什么。如果您可以限制字符串中的char值范围和shift的大小,那么您可能会没事,但我倾向于找到“铸铁”替代方案。 - Jodrell
Jodrell明白了,已经找到了铸铁替代品;)再次感谢。 - Martin Sansone - MiOEE
这个能用于任何字符串吗?比如包含中文字符的字符串? - chriscode
@chriscode 或许吧,但实际上,你可以直接使用一些内置的编码或加密方式,并使用硬编码的密钥。这绝对有效。 - Jodrell
@chriscode,我在回答中加了免责声明。 - Jodrell

11

怎么样:

    Convert.ToBase64String(Encoding.UTF8.GetBytes(myString));

及其逆命题:

    Encoding.UTF8.GetString(Convert.FromBase64String(myObfuscatedString));
只要您不介意字符串长度的增加。

12
除了尺寸增加之外,唯一的缺点就是那个让我一直误以为是base64的“==”终止符。 - Jodrell
@Joe,你能解释一下这个混淆(在位数方面)是做什么的吗? - user2997779
@user2997779 - 它做的就是它名字所说的:将字符串转换为base64编码,如果你查找,你会发现有很多关于这种编码的文档。Base64编码对大多数人来说不容易阅读,因此提供了基本级别的混淆,但这种技术并不打算提供安全性保障。 - Joe
3
@rolls - 如果您关注算法是否容易被猜测,那么您应该使用加密而不是混淆。 - Joe
1
这非常适合混淆。我想要将文件路径+哈希负载掩盖在一个简单的ID字符串中,看起来需要干净利落,加密并不总是关于安全本身。 - Shukri Adams

6

但是你将把密钥存储在哪里? - Jodrell
这是双向的、“不可破解”的,而且很容易实现(与编写自己的“加密器”相比)。 - g t
你的应用程序配置文件,例如在asp中的appsettings。 - middelpat
密钥可以硬编码 - 如果只是为了防止字符串在第三方数据库中可见。 - g t
@gt,当密钥是硬编码时,不可破解的声明是无效的。 - Jodrell
@Jodrell,你说得完全正确——但只有在将进行解码的DLL发送给第三方并被反编译(或密钥变为公共知识)时才是如此。对于一般观察者来说,这些密钥将是“无法破解的”。然而,如果数据很敏感,那么这种方法就不安全了,但也不比使用简单的凯撒密码更不安全 ;) - g t

3

我受到@Jodrell的回答启发,这是我的替代版本。唯一的真正区别是我使用模运算符而不是if-then-else结构。

如果你和我一样以前从未听说过凯撒密码,这里有一个链接:

https://en.wikipedia.org/wiki/Caesar_cipher

   public static partial class MString
   {
      ...

      /// <summary>
      /// Method to perform a very simple (and classical) encryption for a string. This is NOT at 
      /// all secure, it is only intended to make the string value non-obvious at a first glance.
      ///
      /// The shiftOrUnshift argument is an arbitrary "key value", and must be a non-zero integer 
      /// between -65535 and 65535 (inclusive). To decrypt the encrypted string you use the negative 
      /// value. For example, if you encrypt with -42, then you decrypt with +42, or vice-versa.
      ///
      /// This is inspired by, and largely based on, this:
      /// https://dev59.com/8Wcs5IYBdhLWcg3wOBbl#13026595
      /// </summary>
      /// <param name="inputString">string to be encrypted or decrypted, must not be null</param>
      /// <param name="shiftOrUnshift">see above</param>
      /// <returns>encrypted or decrypted string</returns>
      public static string CaesarCipher(string inputString, int shiftOrUnshift)
      {
         // Check C# is still C#
         Debug.Assert(char.MinValue == 0 && char.MaxValue == UInt16.MaxValue);

         const int C64K = UInt16.MaxValue + 1;

         // Check the arguments
         if (inputString == null)
            throw new ArgumentException("Must not be null.", "inputString");
         if (shiftOrUnshift == 0)
            throw new ArgumentException("Must not be zero.", "shiftOrUnshift");
         if (shiftOrUnshift <= -C64K || shiftOrUnshift >= C64K)
            throw new ArgumentException("Out of range.", "shiftOrUnshift");

         // Perform the Caesar cipher shifting, using modulo operator to provide wrap-around
         char[] charArray = new char[inputString.Length];
         for (int i = 0; i < inputString.Length; i++)
         {
            charArray[i] = 
                  Convert.ToChar((Convert.ToInt32(inputString[i]) + shiftOrUnshift + C64K) % C64K);
         }

         // Return the result as a new string
         return new string(charArray);
      }

      ...
   }

还有一些测试代码:

     // Test CaesarCipher() method
     const string CHelloWorld = "Hello world!";
     const int CCaesarCipherKey = 42;
     string caesarCiphered = MString.CaesarCipher(CHelloWorld, CCaesarCipherKey);
     if (MString.CaesarCipher(caesarCiphered, -CCaesarCipherKey) != CHelloWorld)
        throw new Exception("Oh no!");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接