我也需要将数据库的主键(uint)编码为 GUID。关于是否使用单位作为主键或 Guid 有很多讨论,我不会在这里讨论,但我使用 uint 作为主键,使用 guid 作为列,我想将主键编码为guid,然后从 guid 中取回。
以下解决方案将 24 位主键(一个 uint)编码为 Guid,然后将其解码回来。它在 uint 上使用 DES 加密。我认识到这个问题需要一个 32 位 int,这适用于 24 位 uint,但是可以通过连接两个 GUID 来实现 32,一个是最高有效的 24 位,一个是最低有效的 24 位,总共得到 48 位。该算法经过全面测试,可用于 int,但未针对负数进行测试。
GUID 格式
GUID 格式是 32 位数字,可以用连字符分隔,并且包括大括号:00000000-0000-0000-0000-000000000000 (D),即 8-4-4-12 个字符,即 4-2-2- 6 个字节作为 1 个字节被编码为 2 个字符。存在其他格式的 GUID。
3 字节 uint 加密为 8 字节代码,从第 5 个字节开始写入 guid(这是 Guid 的第 10 个字符,忽略括号和“-”分隔符)。让 'z' 表示编码的 int,而 0 表示任何其他十六进制字符。结果编码的 GUID 是
00000000-zzzz-zzzz-zzzz-zzzz00000000
请注意,在此之后 GUID 可能不是全局唯一的。但是,鉴于 GUID 对您的主密钥进行编码,它对于您的主密钥将是唯一的,并且在没有加密密钥的情况下很难从 GUID 中提取 uint ......与 DES 加密一样安全。
public void Test()
{
Guid NewG = Guid.NewGuid();
Guid EnryptedGuid = Utility.EncodeInt24InGUID(NewG, Num);
uint RestoredUint = Utility.DecodeInt24FromGUID(EnryptedGuid);
}
加密
public static Guid EncodeInt24InGUID(Guid guid, uint x)
{
if (x >= Math.Pow(2, 24))
throw new ArgumentOutOfRangeException("Unsigned integer is greater than 24bit");
string strGuid = guid.ToString();
strGuid = Utility.RemoveChars(strGuid, "-{}");//Remove any '-' and '{}' characters
byte[] bytes = BitConverter.GetBytes(x);
var encryptedarray = Cypher.EncryptDES(bytes, Cypher.Key);
string EncryptedGuid = WriteBytesToString(strGuid, encryptedarray, 9);
Guid outg;
Guid.TryParse(EncryptedGuid, out outg);
return outg;
}
RemoveChars 从这里复制/改编 Removing characters from strings with LINQ
WriteBytesToString 如下
public static string WriteBytesToString(string Input, byte[] bytes, int start)
{
StringBuilder g = new StringBuilder(Input);
string temp;
int ByteNum = 0;
int CharPos = start;
int NumBytes = (int)bytes.LongLength;
for (int i = 0; i < NumBytes; i++)
{
temp = string.Format("{0:x2}", bytes[ByteNum++]);
g[CharPos++] = (temp.ToCharArray())[0];
g[CharPos++] = (temp.ToCharArray())[1];
}
return g.ToString();
}
解密
public static uint DecodeInt24FromGUID(Guid guid)
{
string strGuid = guid.ToString();
strGuid = Utility.RemoveChars(strGuid, "-{}");
byte[] EncryptedBytes = GetBytesFromString(strGuid, 9,8);
var decrypted = Cypher.DecryptDES(EncryptedBytes, Cypher.Key);
uint DecryptedUint = BitConverter.ToUInt32(decrypted, 0);
return DecryptedUint;
}
GetBytesFromString。请注意,字节从第 9 个索引开始,并且在调用函数中硬编码为 8 个字节。请参阅有关 GUID 格式的说明
public static byte[] GetBytesFromString(string Input, int start, int NumBytes)
{
StringBuilder g = new StringBuilder(Input);
byte[] Bytes = new byte[NumBytes];
string temp;
int CharPos = start;
for (int i = 0; i < NumBytes; i++)
{
temp = g[CharPos++].ToString();
temp += g[CharPos++].ToString();
Bytes[i] = byte.Parse(temp, System.Globalization.NumberStyles.HexNumber);
}
return Bytes;
}
cyber类是从https://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C这里复制过来的,并适配DES加密。全文贴在下面
using System.IO;
using System.Security.Cryptography;
namespace UtilityLib
{
// This class is adapted from https://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C
public static class Cypher
{
public static string Key = "Asd9847Fg85ihkn52s";
// Encrypt a byte array into a byte array using a key and an IV
public static byte[] EncryptDES(byte[] clearData, byte[] Key, byte[] IV)
{
// Create a MemoryStream to accept the encrypted bytes
MemoryStream ms = new MemoryStream();
TripleDES alg = TripleDES.Create();
alg.Key = Key;
alg.IV = IV;
CryptoStream cs = new CryptoStream(ms,alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.Close();
byte[] encryptedData = ms.ToArray();
return encryptedData;
}
public static byte[] EncryptDES(byte[] clearData, string Password)
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
return EncryptDES(clearData, pdb.GetBytes(24), pdb.GetBytes(8));
}
public static byte[] DecryptDES(byte[] cipherData, byte[] Key, byte[] IV)
{
MemoryStream ms = new MemoryStream();
TripleDES alg = TripleDES.Create();
alg.Key = Key;
alg.IV = IV;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherData, 0, cipherData.Length);
cs.Close();
byte[] decryptedData = ms.ToArray();
return decryptedData;
}
public static byte[] DecryptDES(byte[] cipherData, string Password)
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
return DecryptDES(cipherData, pdb.GetBytes(24), pdb.GetBytes(8));
}
}
}