跳至主要内容

RC4算法的原理和实现

https://ift.tt/2KOKRRr

before learnng

RC4 简介

RC4和DES一样,是一种对称加密算法。通常常听见的对称加密算法是DES,不过RC4和DES不同的是,RC4是以字节流的方式一次加密明文中的每个字节,解密的时候也是以字节流的方式解密密文中的每个字节。

RC4介绍(wikipedia)

RC4的安全性

理论上来讲,RC4是很难通过暴力破解的。RC4中用到的key是[1,256]的unsigned char 字符串,可能性约等于256256 ,量级超级大。当时,如果密钥用的byte比较少那还是挺好爆破的。

算法中的几个关键变量

密钥流

RC4算法的关键是依据明文和密钥生成相应的密钥流。密钥流的长度和明文的长度是相对应的。也就说说明文的长度是500字节,那么密钥流也是500字节,加密生成的密文也是500字节。

密文的第i字节 = 明文的i字节 ^ 密钥流第i字节

状态向量S

长度为256。


S[0],S[1].....S[255]


每一个单元都是一个字节。算法执行的不论什么时候,S都包含0-255 的8比特数的排列组合。仅仅只是值的位置发生了变换。

暂时向量T

长度也为256,每一个单元也是一个字节。

假设密钥的长度是256个字节,那就直接把密钥的值赋给T,否则,轮转的将密钥的每一个字节赋给T。

密钥K

长度为1-256 字节。

注意:密钥的长度keylen 与明文长度,密钥流的长度没有必定关系。

原理

初始化S和T

for (int i = 0; i < 256;++i)
        {
            S[i] = i;
            T[i] = K[i%keylen];
        }

初始化排列S

//目的:让S的位置发生变化,并使得每个
void rangeS(){
        int j = 0;
        for (int i = 0; i < 256;i++)
        {
            j = (j + S[i] + T[i]) % 256;
            S[i] = S[i] + S[j];
            S[j] = S[i] - S[j];
            S[i] = S[i] - S[j];
        }
    }

产生密钥流

   
int i = 0, j = 0, t;
while (len--) //明文的长度
{
    i = (i + 1) % 256;
    j = (j + S[i]) % 256;
    
    S[i] = S[i] + S[j];
    S[j] = S[i] - S[j];
    S[i] = S[i] - S[j];
    t = (S[i] + S[j]) % 256;
    k.push_back(S[t]);
}
        

cpp 工程

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <stdio.h>
using namespace std;
//////////////////////////////////////////////////////////////////////////
//  加密类

class RC4_EN{

public:
    // 构造函数。参数为密钥长度
    RC4_EN(int k1) :keylen(k1){
        srand((unsigned)time(NULL));

        //随机生成长度为keylen字节的密钥

        for (int i = 0; i < k1; ++i)
        {
            int tmp = rand() % 256;
            K.push_back(tmp);
        }
    }


    //初始化向量s和暂时向量T,供keyStream方法调用
    void inital(){
        
        for (int i = 0; i < 256;++i)
        {
            S[i] = i;
            T[i] = K[i%keylen];
        }
    }

    //初始排列状态向量S

    void rangeS(){
        int j = 0;
        for (int i = 0; i < 256;i++)
        {
            j = (j + S[i] + T[i]) % 256;
            S[i] = S[i] + S[j];
            S[j] = S[i] - S[j];
            S[i] = S[i] - S[j];
        }
    }

    //生成密钥流,
    // 参数:密文长度len
    void keystream(int len){
        inital();
        rangeS();
        int i = 0, j = 0, t;
        while (len--)
        {
            i = (i + 1) % 256;
            j = (j + S[i]) % 256;
            
            S[i] = S[i] + S[j];
            S[j] = S[i] - S[j];
            S[i] = S[i] - S[j];
            t = (S[i] + S[j]) % 256;
            k.push_back(S[t]);
        }
    }

    // 由明文产生密文
    void encryption(char* plaintext){
        
        int nTextSize = strlen(plaintext);
        
        //产生密钥流
        keystream(nTextSize);

        unsigned char* cyptertext = new unsigned char[nTextSize]();
        //生成密文
        for (int i = 0; i < nTextSize;i++)
        {
            cyptertext[i] = k[i] ^ plaintext[i];
        }

        //打印明文,密钥,和加密后的密文
        printf("-------加密完成--------------\n");
        printf("明文:%s\n", plaintext);
        printf("密钥流:");
        for (int i = 0; i < k.size();i++)
        {
            printf("%c", k[i]);
        }
        printf("\n");
        printf("密文:%x", cyptertext);

        delete[] cyptertext;

    }
private:
    int keylen;
    unsigned char S[256];//状态向量,共256字节
    unsigned char T[256];//暂时向量,共256字节
    vector<char>K; //可变长度密钥
    vector<char>k;//密钥流


};

int _tmain(int argc, _TCHAR* argv[])
{
    printf("输入加密明文:");
    char plaintext[256] = { 0 };
    scanf_s("%s", plaintext, 256);
    printf("输入密钥长度:");
    int nkeylen = -1;
    scanf_s("%d", &nkeylen, 4);
    RC4_EN rc4_en(nkeylen);
    rc4_en.encryption(plaintext);
    return 0;
}


参考

RC4的破解与防范

The post RC4算法的原理和实现 appeared first on cole.

https://ift.tt/eA8V8J c++ July 06, 2018 at 03:44PM

评论

此博客中的热门博文

反Hook 之自己实现GetProcAddress和LoadLibraryA(c++ version)

http://ift.tt/2AocAD0 // 课上练习.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> //要实现的功能: /* 自己实现GerProcAddress LoadLibraryA */ //思路: /* GerProcAddress和LoadLibraryA都是在Kernel32.dll中的 首要的任务就是找到Kernel32.dll,然后遍历IAT就能找到这两个函数 现在首要的难点就是如何找到kernel32.dll() 通过dll的加载顺序可以找到,而且虽然需要使用未文档化的API,但是好在windgb可以直接看,而且用到的也并不是很多 懒得去晚上搜了,直接自己实现一个得了,作为演示,能用就行(最好还是搜一个正规的结构体) */ /* 0: kd> dt _TEB /a nt!_TEB +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB //首先实现部分TEB结构体,因为只需要用的PEB的部分,所以实现到这就ok了 */ //构建 TEB typedef struct _TEB { //保证0x30是peb的结构体就ok了 struct _tem { DWORD a1; DWORD a2; DWORD a3; DWORD a4; DWORD a5; DWORD a6; DWORD a7; DWORD a8; DWORD a9; DWORD a10; ...

IDA动态调试ELF中遇到的问题(1)

https://ift.tt/2Gxnf2F 遇到 got SIGCHLD singal(child status has changed)...这种提示 singal fork了子进程 直接点yes,然后继续单步执行,出来提示 pass to application就行了 内存查看 用od习惯了之后,凡事都想右键看一下内存,但是IDA中好像没有那么如意, 目前只是在栈中右键发现有查看hex的选项 动态调试的时候的nop ida保存动态调试的时候修改的数据 方法一:在程序运行的时候保存 The post IDA动态调试ELF中遇到的问题(1) appeared first on cole . https://ift.tt/2q9Qf5g WHATEVER April 05, 2018 at 09:44AM

手工加壳Demo- C++Version

http://ift.tt/2AAEutK // 手动加壳demo.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <string.h> typedef struct _StubConf { IMAGE_NT_HEADERS ntheader; }STUBCONF; class PeFile { public: PeFile(); ~PeFile(); bool OpenFile(const char*FilePath); bool InitHdrs(); PIMAGE_SECTION_HEADER addSection(const char * secName, DWORD dwSecSzie); PIMAGE_SECTION_HEADER getSection(const char* secName); DWORD Size2ALi(DWORD dwSize, DWORD dwALi); void peclose(); void setOpe(DWORD newOep); LPVOID peGetProcAddress(const char* szFnName); DWORD RVATOOFFSET(DWORD rva); ULONG_PTR getfileBuff(); PIMAGE_NT_HEADERS getNtHeader(); PIMAGE_OPTIONAL_HEADER getOptionHeader(); void fixStubReloc(DWORD oldImageBase, DWORD newImageBase, DWORD oldSectionRva, DWORD newSectionRva); void setSecData(IMAGE_SECTION_HEADER* pScn, void* pSectionData, DWORD dwSectionSize); bool savea...