2.5 维吉尼亚密码详解及C语言实现-lmn-【密码学】小世界-安全文库-NGC660安全实验室

2.5 维吉尼亚密码详解及C语言实现-lmn

2.5 维吉尼亚密码详解及C语言实现-lmn

1645669092437-d01daf0c-bbe8-4d2f-b406-d5b2a4b591b6

图片地址:https://bkimg.cdn.bcebos.com/pic/3ac79f3df8dcd100d56d833d748b4710b9122f3c?x-bce-process=image/watermark,image_d2F0ZXIvYmFpa2U4MA==,g_7,xp_5,yp_5/format,f_auto

0x01 维吉尼亚密码

这么“炫酷”的表格就是维吉尼亚密码,先看一下百度百科的介绍:
“维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。”

吉奥万·巴蒂斯塔·贝拉索,意大利密码学家。他的主要著作是于1553年出版的《吉奥万·巴蒂斯塔·贝拉索先生的密码》(La cifra del. Sig. Giovan Battista Bellaso)。
贝拉索1505年出生于一个显赫的家庭。他的父亲是皮尔文森佐(Piervincenzo),是布雷西亚的一位贵族,从15世纪起就在镇上和卡普里亚诺(Capriano)郊区拥有一处房产,位于一个叫做Fenili Belasi(贝拉索的谷仓)的社区,包括圣三一教堂。牧师每年得到一笔固定的薪金和一些柴火。家族的纹章是“在蓝色的田野上三个红舌金狮子头在侧面”。
贝拉索精通研究,擅长数学,在当时这种艺术在所有的意大利宫廷,主要是在罗马教廷享有极大的赞赏。在密码学历史的黄金时期,他只是众多秘书中的一个,他们出于对知识的热爱或真正的需要,在日常活动中尝试新的系统。他的密码标志着一个时代,被认为是四个世纪以来破解不了的。

1645669118276-ccbf4e2e-b8ab-4ba7-b3a1-eaab02f77a87

吉奥万·巴蒂斯塔·贝拉索是第一个提出多表密码概念的人,但是后来被误认为是布莱斯·德·维吉尼亚所发明,所以也就称之为维吉尼亚密码

0x02 维吉尼亚密码原理

1645669133885-3f7883e5-a826-46a0-86ba-d52e03342d95

这一一张维吉尼亚的表,可以清楚的看到,这张表由26行,每一行都由前一行字母的顺序向左偏移一位得到

明文为:
VIRGINIACIPHER

密钥为:
SECRETKEY

表格的行代表密钥,列代表明文
明文第1个:V
密文第1个:S 对应密文:N
明文第2个:I
密文第2个:E 对应密文:M
明文第3个:R
密文第3个:C 对应密文:T
明文第4个:G
密文第4个:R 对应密文:X

最后结果为:NMTXMGSEAATJVV
注意:维吉尼亚密码在线加密/解密工具只对字母进行加密,不区分大小写,若文本中出现非字母字符会原样保留!!所以在CTF比赛中可以通过这个很快速的判断出维吉尼亚密码

0x03 维吉尼亚密码CTF题目

题目来自于2022年2月19日的TQLCTF

题目名称:Ranma½

1645669147734-11057eff-b01c-4ef3-bc0d-d3cdacb83dac

一开始并无思路只知道是一个日本动画片,其中的编码方式如下

1645669157725-f78c9b11-b1fa-4ce2-a58c-8d5efc378988

用sublime打开,看到最后应该是flag

1645669167356-a4d52ad2-8e61-429f-b068-7939a6d9f266

再重复一遍重点:维吉尼亚密码在线加密/解密工具只对字母进行加密,不区分大小写,若文本中出现非字母字符会原样保留

1645669177464-490be50d-82b3-498c-af08-32b9f76ece7e

逆推思路其实也不难,在不知道维吉尼亚密码的时候应该怎么解?

前面有一串10646-1,根据搜索知道是ISO/IEC 10646-1,根据ISO/IEC 10646-1内容,推测后面为UTF-8,并通过两个关键词找到原文

网址:https://datatracker.ietf.org/doc/html/rfc3629

1645669187670-09669cff-4245-4488-a376-680896951be8

原文:
ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world’s writing systems. The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo. UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values.

仔细分析两端文字,发现相同的单词对应不同的密文,说明不是替换,并且根据大小写和一些线索也排除了换位密码

通过尝试得到两段的ascii分析,如下图:

1645669197932-c6127122-e6a8-4b16-a1ef-b8ebf5a7a68f

根据相减得到的值,发现可能有循环

1645669207651-76c5403f-23a9-4e7d-b14e-52b9713c5422

根据代码筛选出相减的值,得到循环规律

1645669217677-b4e4357e-2151-4b9c-83eb-d608dbc8c008

以此类推找到flag:TQLCTF{CODIN6_WOQ1D}

不过比赛的时候能省时间还是工具解决吧!

0x04 C语言实现

# -*- coding = utf-8 -*-
# @Time : 2022/2/24 9:03 上午
# @Author : lmn
# @File : Virginia.c
# @Software : CLion

#include <stdio.h>
#include <assert.h>
#define TEXT 100
#define TEXT 100
#define KEY 50

int CHOOSE()
{
    printf("*******************************\n");
    printf("*** 1. 加密  2. 解密  0. 退出****\n");
    printf("*******************************\n");
    int a = 0;
    scanf("%d",&a);
    return a;
}
//计算密文或明文字符长度长度
int TestLen(char* text){
    int sz = 0;
    for(sz=0;text[sz]!='\0';sz++);
    return sz;
}
//初始化
void InitVirginia(char* plaintext, char* ciphertext, char* key){
    int j = 0;
    for (j = 0; j < TEXT; j++) {
        plaintext[j] = ' ';
        ciphertext[j] = ' ';
    }
    for (j = 0; j < KEY; j++) {
        key[j] = ' ';
    }
}
//加密
int ENCODE(char* plaintext, char* key, char* result){
    assert(plaintext && key && result);

    //计算 plaintext 元素个数
    int sz = TestLen(plaintext);

    //计算key元素个数
    int sz2 = TestLen(key);

    int i = 0;
    for(i = 0 ; i < sz ; i++)
    {
        result[i] = (plaintext[i] + key[i % sz2] - 'a'-'a')%26 + 'a';
    }
    printf("\n加密后为:%s\n\n",result);
    return 0;
}
//解密
int DECODE(char* ciphertext, char* key, char* result){
    assert(ciphertext && key && result);

    //计算 ciphertext 元素个数
    int sz = TestLen(ciphertext);

    //计算key元素个数
    int sz2 = TestLen(key);

    int i = 0;
    for(i = 0 ; i < sz ; i++)
    {
        result[i] = (ciphertext[i] + 26 - key[i % sz2])%26 + 'a';
    }
    printf("\n解密后为:%s\n\n",result);
    return 0;
}
int main()
{
    char plaintext[TEXT] = {0};
    char ciphertext[TEXT] = {0};
    char key[KEY] = {0};
    // 1.选择进行的操作
    int a = 1;
    while(a)
    {
        a = CHOOSE();
        if (a == 0)
            break;
        InitVirginia(plaintext, ciphertext, key);
        switch (a) {
            case 1:
                //2.加密
                printf("请输入明文:>");
                scanf("%s",plaintext);
                printf("\n请输入密钥:>");
                scanf("%s",key);
                ENCODE(plaintext,key,ciphertext);
                break;
            case 2:
                //3.解密
                printf("请输入密文:>");
                scanf("%s",ciphertext);
                printf("\n请输入密钥:>");
                scanf("%s",key);
                DECODE(ciphertext, key,plaintext);
                break;

            default:
                printf("输入有误请重新输入!\n\n");

        }
    }
    return 0;
}

功能介绍:

  1. 加了初始化函数InitVirginia,可以循环对维吉尼亚密码进行加解密
  2. 防止功能过度繁杂,每次运算时需要计算长度,所以加入了计算长度的函数TestLen
  3. 防止数组为空,加入了断言
  4. C语言初学者可能有地方写的不标准,欢迎提出

维吉尼亚密码在线工具
https://www.dcode.fr/vigenere-cipher
http://www.atoolbox.net/Tool.php?Id=856

请登录后发表评论

    请登录后查看回复内容