在索普特社区上提出了"Cyraz“加密算法。
该算法使用任意长度的byte[]格式的私钥生成密码。然后,它将“交换”数据上的字节,并在键值上删除。此外,它还会将一个字节附加到密码的末尾,该字节是密钥的散列。因此,该算法只增加1字节的消息大小。
原来的算法只有可用的巴斯托。此实现只处理byte[]格式的数据。我的工作是让它也处理Streams,这样算法就能够处理内存中不合适的文件。当使用流接口加密数据时,我也需要它与数组接口一起工作。为了完成这项工作,我添加了一个额外的页脚(2个字节),它告诉我数据是否已经使用流加密。
我们知道这个密码很容易破坏,所以请考虑这是一个“玩具”密码。
public class Cryraz {
private byte[] key = new byte[0];
private const int bufferLength = 4096;
//footer to include when encrypting data as a stream
private static readonly byte[] streamFooter = new byte[]{255, 255};
/// <summary>
/// Represents the standart operation for encrypting or decrypting types.
/// </summary>
public enum Operation {
/// <summary>
/// Byte decrypting algorithin.
/// </summary>
Decrypt,
/// <summary>
/// Byte encrypting algorithin.
/// </summary>
Encrypt
}
/// <summary>
/// Creates a new <seealso cref="Cryraz"/> instance with specified key array.
/// </summary>
/// <param name="key">The new instance byte-based key.</param>
public Cryraz(byte[] key){
if(key == null){
throw new ArgumentNullException(nameof(key));
}
this.key = key;
}
/// <summary>
/// Updates the key. You cannot get it directly.
/// </summary>
public byte[] Key { set { key = value; } }
internal static byte performKeyHash(byte[] key) {
int x = 0;
foreach (byte b in key) {
x += b;
x *= 1 + (b % 2);
}
return (byte)(x / key.Length);
}
internal static byte computePos(byte[] inputArray, int pos) {
int length = inputArray.Length;
if (pos <= length - 1) return inputArray[pos];
int divisor = pos / length;
pos -= length * divisor;
return inputArray[pos];
}
/// <summary>
/// Validates if the file can be decrytped with the current key
/// </summary>
/// <param name="data">The encrypted data</param>
/// <returns>True if the file was encrypted with streams</returns>
private bool Verify(byte[] data){
if (data == null)
throw new ArgumentNullException("entryByteData", "Input data cannot be nothing.");
var length = data.Length;
var isStreamEncrypted = data.Length >= streamFooter.Length + 1;
for(int i = 1; i <= streamFooter.Length; ++i){
isStreamEncrypted &= data[length - i] == streamFooter[streamFooter.Length - i];
}
var checkSum = isStreamEncrypted ? data[length - streamFooter.Length - 1] : data[length - 1];
byte hash_x = performKeyHash(key);
if (hash_x != checkSum)
throw new System.Security.SecurityException("Invalid key for this data.");
return isStreamEncrypted;
}
private Stream DecryptData(Stream reader, bool createFile, bool verify){
var isStream = !verify;
if(verify){
reader.Position = reader.Length - streamFooter.Length - 1;
var footer = new byte[streamFooter.Length + 1];
reader.Read(footer, 0, footer.Length);
isStream = Verify(footer);
reader.Position = 0;
}
if(!isStream){
var memStream = new MemoryStream();
reader.CopyTo(memStream);
var data = memStream.ToArray();
return DecryptData(ref data, createFile);
}
var writer = createFile
? (Stream)File.Create(Path.GetTempFileName())
: (Stream)new MemoryStream();
var buffer = new byte[bufferLength];
int bytes;
while((bytes = reader.Read(buffer, 0, buffer.Length)) > 0){
Array.Resize(ref buffer, bytes);
performData(ref buffer, Operation.Decrypt, 0);
writer.Write(buffer, 0, bytes);
}
if(verify){
writer.SetLength(writer.Length - streamFooter.Length - 1);
}
writer.Flush();
writer.Position = 0;
return writer;
}
public Stream DecryptData(Stream stream, bool createFile = false) {
return DecryptData(stream, createFile, true);
}
/// <summary>
/// Decrypts an given single dimension byte-array with this class key.
/// </summary>
/// <param name="entryByteData">The input byte-array to decrypting.</param>
/// <returns>A temporary file path containing the decrypted data if createFile is true.
/// Null if createFile is false</returns>
public Stream DecryptData(ref byte[] data, bool createFile = false) {
var isStreamEncrypted = Verify(data);
if(!isStreamEncrypted){
performData(ref data, Operation.Decrypt, 0);
data[data.Length - 1] = 0;
Array.Resize(ref data, data.Length - 1);
var writer = createFile
? (Stream)File.Create(Path.GetTempFileName())
: (Stream)new MemoryStream(data);
return writer;
}else{
Array.Resize(ref data, data.Length - streamFooter.Length - 1);
var stream = DecryptData(new MemoryStream(data), createFile, false);
stream.Read(data, 0, data.Length);
stream.Position = 0;
return stream;
}
}
/// <summary>
/// Encrypts an given single dimension byte-array with this class key.
/// </summary>
/// <param name="entryByteData">The input byte-array to encrypting.</param>
public void EncryptData(ref byte[] entryByteData, bool createFile = false) {
if (entryByteData == null)
throw new ArgumentNullException("entryByteData", "Input data cannot be nothing.");
performData(ref entryByteData, Operation.Encrypt, 0);
Array.Resize(ref entryByteData, entryByteData.Length + 1);
byte hash_x = performKeyHash(key);
entryByteData[entryByteData.Length - 1] = hash_x;
}
public Stream EncryptData(Stream stream, bool createFile = false) {
if (stream == null)
throw new ArgumentNullException("stream", "Input data cannot be nothing.");
var writer = createFile
? (Stream)File.Create(Path.GetTempFileName())
: (Stream)new MemoryStream();
byte hash = performKeyHash(key);
var buffer = new byte[bufferLength];
int bytes;
while((bytes = stream.Read(buffer, 0, buffer.Length)) > 0){
Array.Resize(ref buffer, bytes);
performData(ref buffer, Operation.Encrypt, 0);
writer.Write(buffer, 0, bytes);
}
writer.WriteByte(hash);
writer.Write(streamFooter, 0, streamFooter.Length);
writer.Position = 0;
return writer;
}
internal void performData(ref byte[] entryByteData, Operation op, int keyOffset) {
for (int i = 0; i <= entryByteData.Length - 1; i++) {
int pos = computePos(key, keyOffset + i);
int a = entryByteData[i];
if (op == Operation.Encrypt) {
a += pos;
} else a -= pos;
entryByteData[i] = ((byte)a);
}
}
}还有一个样本来测试它。(不供审查)
public class Sample{
public static void Main(string[] args)
{
var cypher = new Cryraz(new byte[]{10, 11, 12});
var original = Enumerable.Range(0 , 1024 * 1024).
Select(i => (byte)(i % (byte.MaxValue + 1)))
.ToArray();
var data = new byte[original.Length];
Array.Copy(original, data, original.Length);
var sum = data.Sum(d => (long)d);
cypher.EncryptData(ref data);
cypher.DecryptData(ref data, false);
if(!Enumerable.SequenceEqual(original, data)){
Console.WriteLine("Can not encrypt and desencrypt arrays");
}else{
Console.WriteLine("Can encrypt and desencrypt arrays");
}
var stream = cypher.EncryptData(new MemoryStream(data)) as MemoryStream;
var memStream = cypher.DecryptData(stream) as MemoryStream;
data = memStream.ToArray();
if(!Enumerable.SequenceEqual(original, data)){
Console.WriteLine("Can not encrypt and desencrypt streams");
}else{
Console.WriteLine("Can encrypt and desencrypt streams");
}
memStream = cypher.EncryptData(new MemoryStream(data)) as MemoryStream;
data = memStream.ToArray();
cypher.DecryptData(ref data);
if(!Enumerable.SequenceEqual(original, data)){
Console.WriteLine("Can not encrypt streams and desencrypt arrays");
}else{
Console.WriteLine("Can encrypt streams and desencrypt arrays");
}
cypher.EncryptData(ref data);
memStream = cypher.DecryptData(new MemoryStream(data)) as MemoryStream;
data = memStream.ToArray();
if(!Enumerable.SequenceEqual(original, data)){
Console.WriteLine("Can not encrypt arrays and desencrypt streams");
}else{
Console.WriteLine("Can encrypt arrays and desencrypt streams");
}
}
}发布于 2017-07-09 12:36:34
您在代码中使用了一些非标准循环。
for (int i= 1;i <= streamFooter.Length;++i)
应该有一个注释来解释为什么这个循环是从1开始的,而不是0预期的。我想这是有原因的。更好的方法是为const定义一个1,它可以解释这个偏移量,而不需要评论。
(int i= 0;i <= entryByteData.Length - 1;i++)
我必须承认,我从未见过像这样编写的for循环。我们通常不编写- 1,而是使用更简单的<条件而不是<=。大多数API认为上限是排他性的(比如Enumerable.Repeat或Random.Next)。这是一种更流行的形式:
for (int i = 0; i < entryByteData.Length; i++)var memStream =新的MemoryStream();
你没有处理你的溪流。(我知道,有传言说有些一次性物品不需要实际处理,但最好总是这样做。实现可能会改变)。
如果(核实)
当我看到verify参数时,我想要验证什么?表达不够。
内部空洞performData(ref byte[] entryByteData,Operation op,int keyOffset)
第一个参数使用一个很好的描述性名称,但操作只使用两个字母:( Operation枚举也需要升级。什么手术?
否则是-=的pos;
奥奇!不仅缺少{},而且变量名只是一个a。
发布于 2017-07-10 08:53:07
┻━┻︵}{︵┻━┻
操作符和大括号之间的一些空格会很好。一件小事,但它确实有助于阅读代码。
发布于 2017-07-10 10:30:03
我不确定C#是否有什么特别之处,但是您代码的这一部分引起了我的注意:
变量isStream =!reader.Length;if(验证){ reader.Position =reader.Length- streamFooter.Length - 1;var页脚=新字节streamFooter.Length +1;reader.Read(页脚,0,footer.Length);isStream =验证(页脚);reader.Position = 0;} if(!isStream){ var memStream =新MemoryStream();reader.CopyTo(memStream);var data =memStream.ToArray;返回DecryptData(参考数据,createFile);
我无法将变量的含义从它们的名称中连接起来,而且看起来,如果一个if被执行,另一个也必须执行。
https://codereview.stackexchange.com/questions/168747
复制相似问题