首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >国产cyraz加密算法

国产cyraz加密算法
EN

Code Review用户
提问于 2017-07-09 12:00:10
回答 4查看 1.9K关注 0票数 11

索普特社区上提出了"Cyraz“加密算法。

该算法使用任意长度的byte[]格式的私钥生成密码。然后,它将“交换”数据上的字节,并在键值上删除。此外,它还会将一个字节附加到密码的末尾,该字节是密钥的散列。因此,该算法只增加1字节的消息大小。

原来的算法只有可用的巴斯托。此实现只处理byte[]格式的数据。我的工作是让它也处理Streams,这样算法就能够处理内存中不合适的文件。当使用流接口加密数据时,我也需要它与数组接口一起工作。为了完成这项工作,我添加了一个额外的页脚(2个字节),它告诉我数据是否已经使用流加密。

我们知道这个密码很容易破坏,所以请考虑这是一个“玩具”密码。

代码语言:javascript
复制
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);
        }
    }
}

还有一个样本来测试它。(不供审查)

代码语言:javascript
复制
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");
        }
    }
}
EN

回答 4

Code Review用户

回答已采纳

发布于 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.RepeatRandom.Next)。这是一种更流行的形式:

代码语言:javascript
复制
for (int i = 0; i < entryByteData.Length; i++)

var memStream =新的MemoryStream();

你没有处理你的溪流。(我知道,有传言说有些一次性物品不需要实际处理,但最好总是这样做。实现可能会改变)。

如果(核实)

当我看到verify参数时,我想要验证什么?表达不够。

内部空洞performData(ref byte[] entryByteData,Operation op,int keyOffset)

第一个参数使用一个很好的描述性名称,但操作只使用两个字母:( Operation枚举也需要升级。什么手术?

否则是-=的pos;

奥奇!不仅缺少{},而且变量名只是一个a

票数 17
EN

Code Review用户

发布于 2017-07-10 08:53:07

┻━┻︵}{︵┻━┻

操作符和大括号之间的一些空格会很好。一件小事,但它确实有助于阅读代码。

票数 4
EN

Code Review用户

发布于 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被执行,另一个也必须执行。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/168747

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档