Skip to content

aZerinChan/infosec

Repository files navigation

The first homework(与网络(信息)安全相关的事件)

定义:

网络安全事件是指由于人为原因、软硬件缺陷或故障、自然灾害等,对网络和信息系统或者其中的数据造成危害,对社会造成负面影响的事件。 什么是“网络安全事件”?--信息安全

事件及评价:

  1. 2022年1月,美国Broward Health公共卫生系统公布了一起大规模数据泄露事件,超130万人受到该事件影响。该医疗系统的一个第三方供应商遭到黑客攻击,导致患者的姓名、地址、电话号码、出生日期等个人信息被盗取。这是一起典型的信息破坏事件,暴露了医疗机构在保护个人隐私方面的不足,可能给受影响的患者带来诸如身份盗用等风险。 https://www.thepaper.cn/newsDetail_forward_18916158
  2. 2022年4月,世界各地频发勒索软件攻击,包括美国石油管道公司Colonial Pipeline、爱尔兰卫生服务局、新西兰医院等都遭到黑客勒索。我认为这是一系列有组织、有目的的网络攻击事件,威胁了关键基础设施和公共服务的正常运行。 https://xxb.gdufe.edu.cn/2022/0408/c6341a157111/page.htm
  3. 2022年6月,斯诺登泄密事件十周年纪念日前夕,美国国家安全局(NSA)承认其监视计划违反了美国宪法,并表示已经停止部分收集活动。我认为这是一个具有历史意义的网络安全事件,揭露了美国及其“五眼联盟”在911袭击后建立的全球监视网络。 https://www.freebuf.com/articles/network/221984.html
  4. 2021年1月,疑似超2亿国内个人信息在国外暗网论坛兜售,包括姓名、手机号、身份证号、地址等敏感信息。我认为这是一起严重的信息内容安全事件,暴露了个人信息保护的缺失和漏洞。 https://www.thepaper.cn/newsDetail_forward_17013245
  5. 2021年3月,微软披露了其Exchange Server邮件服务器软件存在四个严重的漏洞,这些漏洞被黑客利用来窃取电子邮件和部署恶意软件。据估计,至少有25万台服务器受到影响。这是一起典型的漏洞攻击(属于网络攻击类别)事件,暴露了微软在维护其产品安全方面的不力,可能给企业和政府机构带来巨大损失。 https://new.qq.com/rain/a/20210107a0273m00
  6. 2021年5月,美国殖民管道公司遭到勒索软件攻击,导致其运输石油和天然气的管道系统停止运行。该公司最终向黑客支付了450万美元赎金以恢复其服务。这是一起典型的勒索软件(属于网络攻击类别)事件,暴露了美国在保护其关键基础设施方面的薄弱环节,可能给能源供应和国家安全带来严重威胁。 https://new.qq.com/rain/a/20220118A05Q1300
  7. 2019年6月,前美国中央情报局(CIA)雇员爱德华·斯诺登向媒体泄露了美国及其“五眼联盟”在911袭击后建立的全球监视网络。该监视网络涉及对数十亿人的通信数据和互联网活动进行拦截和分析。这是一起典型的信息内容安全事件,暴露了政府机构在侵犯公民隐私方面的滥权行为,引发了全球范围内对网络监管和数据保护的广泛讨论。 https://www.freebuf.com/articles/network/221984.html
  8. 2021年7月,全球最大的云计算服务商之一亚马逊遭到一起数据泄露事件,导致超过10亿条用户数据被公开暴露在网上。这些数据包括用户姓名、电子邮件地址、电话号码、生日等敏感信息。这是一起典型的数据泄露(属于信息破坏类别)事件,暴露了亚马逊在保护用户隐私方面的疏忽大意,可能给用户带来诸如身份盗用等风险。 https://www.thepaper.cn/newsDetail_forward_18916158

The second homework(隐私)

隐私泄露的定义

隐私泄露是指个人或组织的敏感或机密信息被未经授权的人或实体获取、使用或公开。隐私泄露可能会导致个人或组织的财产损失、信誉受损、法律责任、身份盗用等风险。

事件

2022年,全球发生了多起数据泄露事件,涉及政府部门、国际组织、门户网站、国防机构、航空公司、银行、汽车制造商、学校、酒店、医疗等行业。其中,一些比较引人关注的事件有:

  1. 1月,美国联邦调查局(FBI)和美国司法部(DOJ)承认在去年12月发生的太阳风暴网络攻击中,他们的内部系统遭到入侵,数千名员工和承包商的个人信息被泄露。
  2. 3月,Facebook再次爆出数据泄露丑闻,超过5.3亿用户的个人信息被公开出售,包括姓名、电话号码、电子邮件地址等。
  3. 6月,印度最大的在线旅游平台MakeMyTrip遭到黑客攻击,约1.8亿用户的数据被窃取,并在暗网上出售。
  4. 9月,中国最大的房地产公司恒大集团因债务危机引发社会动荡,在此期间有消息称其内部员工和客户的数据被泄露,并有不法分子利用这些数据进行诈骗活动。
  5. 11月,英国最大的电信运营商BT Group承认其旗下子公司EE在今年4月至8月期间发生了一起数据泄露事件,影响了约18万名客户。

评价:

  • 数据泄露是一个严重而普遍的问题,需要各方共同努力来防范和应对。个人或组织应该加强自身的安全意识和保护措施,如使用强密码、定期更换账号信息、不随意点击可疑链接等。
  • 数据泄露不仅会给当事者带来直接和间接的损失,还可能会威胁到社会秩序和国家安全。因此,在法律层面上也应该建立健全相关规定和制度,对于违法行为要严惩不贷,并提高公众对于隐私权利和义务的认知。
  • 数据泄露也反映了当前互联网技术发展与隐私保护之间存在着一定程度的矛盾和冲突。在享受网络便利与服务时,我们也要注意保护自己和他人的隐私,并尊重他人对于自己信息处理方式和范围的选择。

参考资料:

(1) 盘点 I 2022年数据泄露事件_腾讯新闻 (2) 2020年全球数据泄露大事件盘点:数据“裸奔” 代价 (3) 近几年网络隐私泄露的经典案例都有哪些? - 知乎

The third homework(基于角色的访问控制和基于身份的访问控制)

RBAC的定义

基于角色的访问控制(Role-based access control, RBAC)是一种访问控制方法,可根据最终用户在组织中的角色为其分配权限。RBAC 允许用户或组拥有访问和管理资源的特定权限。RBAC 是一种安全功能,用于控制用户对通常仅限于超级用户的任务的访问。RBAC 是基于角色的访问控制(Role-Based Access Control ),在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。

参考资料:

(1) 什么是基于角色的访问控制 (RBAC)?示例、好处等 .... (2) 在应用程序中实现基于角色的访问控制 - Microsoft Entra .... (3) 基于角色的访问控制(概述) - 系统管理指南:安全 .... (4) RBAC-基于角色的访问控制 - 腾讯云开发者社区-腾讯云 (5) 什么是 Azure 基于角色的访问控制 (Azure RBAC)?

RBAC的优点和缺点

RBAC 的优点包括易于管理和扩展,可以轻松捕获组织的结构,有助于风险评估和事件分析,可以控制用户对通常仅限于超级用户的任务的访问,以及可以根据最终用户在组织中的角色为其分配权限¹。RBAC 的缺点包括策略是粗粒度的,尝试更精细的粒度通常会导致角色爆炸,不支持基于时间、日期、位置等参数的授权,这使得在动态环境中使用它具有挑战性,通过角色工程创建 RBAC 策略是一项复杂且耗费资源的任务。

参考资料:

(1) RBAC(DAC)模型 (2) 被推荐人优缺点怎么写_百度知道 (3) RBAC用户、角色、权限、组设计方案 - 知乎 (4) 10、RBAC模型概述_执手天涯@的博客-CSDN博客 (5) RBAC(DAC)模型

RBAC的实现方式

RBAC 的实现方式通常是通过数据库来实现的。RBAC 有两种实现方式:基于角色的访问控制和基于任务的访问控制。基于角色的访问控制是指将权限授予角色,然后将角色授予用户,而基于任务的访问控制是指将权限授予任务,然后将任务授予用户。

参考资料:

(1) RBAC是什么?怎么实现RBAC ?附表结构_YangJianYong_Geek的 .... (2) 权限系统设计模型分析(DAC,MAC,RBAC,ABAC) (3) RBAC权限系统分析、设计与实现_rbac权限管理_lvshuocool的 ... (4) RBAC权限系统分析、设计与实现(首先,本质上角色 ...

RBAC的应用场景

RBAC 的应用场景包括但不限于:企业内部的权限管理、网络安全、操作系统安全、数据库安全、应用程序安全等。

参考资料:

(1) RBAC模型:基于用户-角色-权限控制的一些思考 | 人人 ... (2) RBAC用户、角色、权限、组设计方案 - 知乎 (3) 深入理解 RBAC - 掘金

IBAC的定义

基于身份的访问控制(Identity-Based Access Control,IBAC)是一种访问控制模型,它基于用户的身份信息来控制对资源的访问权限。访问控制是指在鉴别用户的合法身份后,通过某种途径准许或限制用户对数据信息的访问能力及范围,阻止未经授权的资源访问,包括阻止以未经授权的方式使用资源。身份认证是访问控制的第一步,它是确认用户身份的过程。身份认证可以使用密码、数字证书、生物识别技术等方式进行。

参考资料:

(1) ChatGPT扫盲大数据_Singlerr的博客-CSDN博客 (2) 访问控制(相关概述)_三只猫兄弟的博客-CSDN博客 (3) 网络安全第三讲 身份认证与访问控制 - 腾讯云开发者 ... (4) 访问控制技术_百度百科 (5) [访问控制概述 | Microsoft Learn. https://learn.microsoft.com/zh-cn/windows/security/identity-protection/access-control/access-control) (6) 信息安全中的访问控制 - 知乎

IBAC的优点和缺点

基于身份的访问控制(Identity-Based Access Control,IBAC)是一种访问控制模型,它使用用户的身份信息来控制对资源的访问。IBAC的优点是可以更好地保护资源的安全性,因为它可以更好地控制对资源的访问。此外,IBAC还可以更好地保护用户的隐私,因为它可以更好地控制用户的身份信息。IBAC的缺点是需要更多的管理和维护,因为它需要更多的身份验证和授权。

参考资料:

(1) 网络安全第三讲 身份认证与访问控制 - 腾讯云开发者 ... (2) 信息安全中的访问控制 - 知乎 (3) 访问控制模型综述 - 知乎

IBAC的实现方式

IBAC的实现方式是通过对主体进行身份验证,然后根据主体的身份来控制其对资源的访问。IBAC是一种基于身份的访问控制(Identification-based Access Control Policies)的实现方式。IBAC的实现方式是通过对主体进行身份验证,然后根据主体的身份来控制其对资源的访问。IBAC的实现方式是通过对主体进行身份验证,然后根据主体的身份来控制其对资源的访问。¹

参考资料:

(1) 基于属性的访问控制(ABAC)定义与思考 ——ABAC的 ... (2) 史上最强的权限系统设计攻略(下)、ABAC在复杂场景下 ... (3) 从RNN到“只要注意力”——Transformer模型 - 知乎

IBAC的应用场景

  • 企业内部的访问控制
  • 云计算环境下的访问控制
  • 电子商务中的访问控制
  • 金融领域的访问控制
  • 医疗领域的访问控制

参考资料:

(1) 类器官芯片的意义及应用价值 - 知乎 (2) 史上最强的权限系统设计攻略(下)、ABAC在复杂场景下 ... (3) SLAM入门+典型SLAM应用及解决方案 - 知乎

IBAC和RBAC的区别

  • RBAC是基于角色的访问控制,而IBAC是基于生物模拟的访问控制。
  • RBAC是一种静态的访问控制,而IBAC是一种动态的访问控制。
  • RBAC是一种基于用户、角色和权限的访问控制,而IBAC是一种基于生物模拟的访问控制,它使用生物学上的屏障作为模型来模拟不同层次之间的访问控制。

参考资料:

(1) NGAC vs RBAC vs ABAC 及为何选择 NGAC 作为权限控制模型 - 知乎 (2) RBAC模型:基于用户-角色-权限控制的一些思考 | 人人 ... (3) 详细了解RBAC(Role-Based Access Control) - 知乎

The fourth homework(隐通道)

定义

  1. B.W.Lampson给出的定义:隐通道是指违背设计者的原意和初衷,被用来通信的通道。
  2. TCSEC的定义:隐通道是一个通信通道,它使得一个进程能以违反系统安全策略的方式违背信息。
  3. NCSCC(美国国家计算机安全中心)的定义:给定一个非自主安全 策略模型M和它在一个操作系统中的实现I(M),I(M)中的两个主体I(si)和I(sj)之间的通信是隐蔽的,当且仅当模型M中相应的两个主体si和sj之间的通信是非法的。

参考资料: (1) 隐通道_百度百科 (2) 隐蔽通道_百度百科

隐通道的案例

  • 磁盘移臂隐通道:利用磁盘移臂的位置来传递信息,例如移动到偶数扇区表示0,移动到奇数扇区表示1。
  • 文件节点号信道:利用文件系统中文件的节点号来传递信息,例如节点号为偶数表示0,为奇数表示1。
  • DNS隐蔽信道:利用DNS协议中的域名查询或响应来传递信息,例如在域名中嵌入加密或编码后的数据。
  • ICMP隐蔽信道:利用ICMP协议中的回显请求或回显应答来传递信息,例如在数据部分携带加密或编码后的数据。

参考资料:

(1) 隐通道_360百科 (2) 6.8 隐蔽通道构造场景与实例分析(含演示) (3) 隐蔽信道:隐形网络 - 知乎 (4) [(9)隐蔽通道重点知识复习笔记_康雨城的博客-CSDN博客](https://blog.csdn.net/kangyucheng/article/ 隐通道

The fifth homework(凯撒密码)

凯撒密码的加密与解密

源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LEN 10000

void caesar_encrypt(char* message, int shift);

int main()
{
    FILE* input_file, * output_file;
    char input_filename[100], output_filename[100];
    char message[MAX_LEN];
    int shift;

    // 输入要(加密/解密)的文件名和移位数
    printf("请输入要(加密/解密)的文件名:");
    scanf("%s", input_filename);

    printf("请输入移位数:");
    scanf("%d", &shift);
    for (shift; shift < 0; shift += 26);
    shift = shift % 26;
    // 打开要(加密/解密)的文件
    input_file = fopen(input_filename, "r");
    if (input_file == NULL)
    {
        printf("无法打开文件:%s\n", input_filename);
        exit(1);
    }

    // 读取文件内容
    fgets(message, MAX_LEN, input_file);
    message[strcspn(message, "\n")] = 0;

    // 对文件内容进行(加密/解密)
    caesar_encrypt(message, shift);

    // 关闭文件
    fclose(input_file);

    // 输出(加密/解密)后的内容
    printf("(加密/解密)后的内容:%s\n", message);

    // 保存(加密/解密)后的内容到文件
    printf("请输入保存(加密/解密)后内容的文件名:");
    scanf("%s", output_filename);

    output_file = fopen(output_filename, "w");
    if (output_file == NULL)
    {
        printf("无法打开文件:%s\n", output_filename);
        exit(1);
    }

    fputs(message, output_file);

    fclose(output_file);

    printf("(加密/解密)后的内容已保存到文件:%s\n", output_filename);

    return 0;
}

void caesar_encrypt(char* message, int shift)
{
    int i;
    char ch;
    for (i = 0; message[i] != '\0'; i++)
    {
        ch = message[i];
        if (ch >= 'a' && ch <= 'z')
        {
            ch = (ch + shift - 'a') % 26 + 'a';
        }
        else if (ch >= 'A' && ch <= 'Z')
        {
            ch = (ch + shift - 'A') % 26 + 'A';
        }
        message[i] = ch;
    }
}

说明

这段代码中定义了一个caesar_encrypt函数,用于对字符串进行凯撒密码加密/解密操作。该函数接受两个参数,第一个参数是要加密/解密的字符串,第二个参数是移位数。函数中的循环遍历字符串中的每个字符,并根据其ASCII码值进行加密/解密操作。具体来说,如果字符是小写字母,则将其移位后再加上小写字母'a'的ASCII码值,然后对26取余,最后再加上小写字母'a'的ASCII码值;如果字符是大写字母,则同理。

运行结果

源程序

凯撒密码加密与解密

频率分析法攻击凯撒密码

源代码

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX_LEN 10000

void caesar_encrypt(char* message, int shift);

int main() {
    char filename[100];
    printf("Enter the name of the file containing the ciphertext: ");
    scanf("%s", filename);

    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        printf("Could not open file %s\n", filename);
        return 1;
    }

    int letter_counts[26] = { 0 };
    int total_letters = 0;
    char line[1000];

    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = '\0';  // remove trailing newline
        for (int i = 0; line[i] != '\0'; i++) {
            if (isalpha(line[i])) {
                line[i] = tolower(line[i]);
                int index = line[i] - 'a';
                letter_counts[index]++;
                total_letters++;
            }
        }
    }

    fclose(file);

    printf("Letter frequency analysis for ciphertext:\n");
    printf("Total letters analyzed: %d\n", total_letters);

    for (int i = 0; i < 26; i++) {
        double frequency = (double)letter_counts[i] / total_letters;
        printf("%c: %.2f%%\n", 'a' + i, frequency * 100);
    }

    int max_index = 0;
    for (int i = 1; i < 26; i++) {
        if (letter_counts[i] > letter_counts[max_index]) {
            max_index = i;
        }
    }

    int key = (max_index - ('e' - 'a') + 26) % 26;
    printf("Probable key: %d\n", key);

    FILE* input_file, * output_file;
    char output_filename[100];
    char message[MAX_LEN];
    int shift = 26 - key;

    // 打开要解密的文件
    input_file = fopen(filename, "r");
    if (input_file == NULL)
    {
        printf("无法打开文件:%s\n", filename);
        exit(1);
    }

    // 读取文件内容
    fgets(message, MAX_LEN, input_file);
    message[strcspn(message, "\n")] = 0;

    // 对文件内容进行解密
    caesar_encrypt(message, shift);

    // 关闭文件
    fclose(input_file);

    // 输出解密后的内容
    printf("解密后的内容:%s\n", message);

    // 保存解密后的内容到文件
    printf("请输入保存解密后内容的文件名:");
    scanf("%s", output_filename);

    output_file = fopen(output_filename, "w");
    if (output_file == NULL)
    {
        printf("无法打开文件:%s\n", output_filename);
        exit(1);
    }

    fputs(message, output_file);

    fclose(output_file);

    printf("解密后的内容已保存到文件:%s\n", output_filename);
    return 0;
}

void caesar_encrypt(char* message, int shift)
{
    int i;
    char ch;
    for (i = 0; message[i] != '\0'; i++)
    {
        ch = message[i];
        if (ch >= 'a' && ch <= 'z')
        {
            ch = (ch + shift - 'a') % 26 + 'a';
        }
        else if (ch >= 'A' && ch <= 'Z')
        {
            ch = (ch + shift - 'A') % 26 + 'A';
        }
        message[i] = ch;
    }
}

说明

程序的大致流程如下:

  1. 读取一个密文文件,统计各个字母的出现频率。
  2. 根据出现频率最高的字母来猜测密钥。
  3. 读取待解密的文件。
  4. 对文件内容进行解密,得到明文。
  5. 将解密后的明文保存到文件中。

这个程序实现了凯撒密码的基本功能,但也存在一些问题:

  1. 猜测密钥的方法过于简单,只是找出出现频率最高的字母,而没有考虑英文中常用字母的出现概率,容易出现误判。
  2. 密文文件的读取方式只考虑了每行最多1000个字符,可能存在读取不完整的情况。
  3. 解密函数中使用了硬编码的字符范围,不够通用。

运行结果

源程序

频率分析法攻击凯撒密码

穷举攻击凯撒密码

源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LEN 10000


void caesar_encrypt(char* message, int shift);

int main()
{
    FILE* input_file, * output_file;
    char input_filename[100], output_filename[100];
    char message[MAX_LEN];
    int shift = 1;

    // 输入要解密的文件名和移位数
    printf("请输入要解密的文件名:");
    scanf("%s", input_filename);

    // 打开要解密的文件
    input_file = fopen(input_filename, "r");
    if (input_file == NULL)
    {
        printf("无法打开文件:%s\n", input_filename);
        exit(1);
    }

    // 保存解密后的内容到文件
    printf("请输入保存解密后内容的文件名:");
    scanf("%s", output_filename);

    output_file = fopen(output_filename, "w");
    if (output_file == NULL)
    {
        printf("无法打开文件:%s\n", output_filename);
        exit(1);
    }

    // 读取文件内容
    fgets(message, MAX_LEN, input_file);
    message[strcspn(message, "\n")] = 0;


    for (; shift < 26; shift++) {
        // 对文件内容进行解密
        caesar_encrypt(message, 1);
        printf("\nkey%d:\n", 26 - shift);
        // 输出解密后的内容
        printf("解密后的内容:%s\n", message);
        fprintf_s(output_file, "\nkey%d:\n", 26 - shift);
        fputs(message, output_file);
    }

    // 关闭文件
    fclose(input_file);
    fclose(output_file);

    printf("/n解密后的内容已保存到文件:%s\n", output_filename);

    return 0;
}

void caesar_encrypt(char* message, int shift)
{
    int i;
    char ch;
    for (i = 0; message[i] != '\0'; i++)
    {
        ch = message[i];
        if (ch >= 'a' && ch <= 'z')
        {
            ch = (ch + shift - 'a') % 26 + 'a';
        }
        else if (ch >= 'A' && ch <= 'Z')
        {
            ch = (ch + shift - 'A') % 26 + 'A';
        }
        message[i] = ch;
    }
}

说明

首先从用户那里输入要解密的文件名和保存解密后内容的文件名,然后打开输入文件和输出文件。接着,读取输入文件中的内容,对内容进行解密,并保存解密后的内容到输出文件中。最后,关闭输入文件和输出文件,并提示用户解密后的内容已保存到输出文件中。在具体实现中,程序先读取文件中的内容,然后用穷举法循环对内容进行解密,并输出解密后的内容。

运行结果

源程序

穷举攻击凯撒密码

The sixth homework(维吉尼亚密码)

定义

维吉尼亚密码是一种由凯撒密码为基础组成的多表密码,该密码算法最早由吉奥万·巴蒂斯塔·贝拉索所发明,但被误以为是法国人布莱斯·德·维吉尼亚所发明,因此该名称被称为维吉尼亚密码。维吉尼亚密码是一种简单的多表代换密码,即由一些偏移量不同的恺撒密码组成,这些代换在一起组成了密钥。维吉尼亚密码的密钥是一个单词或短语,这个密钥会被重复使用,直到密文长度与明文长度相等为止。维吉尼亚密码的加密过程是将明文中的每个字母通过密钥中对应位置的字母进行移位得到密文。

源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LEN 1000

// 声明函数
void encrypt(char* input_file, char* output_file, char* key);
void decrypt(char* input_file, char* output_file, char* key);
void print_file(char* filename);

int main()
{
    char input_file[MAX_LEN], output_file[MAX_LEN], key[MAX_LEN];
    int choice;

    // 获取用户选择
    printf("请选择操作:\n");
    printf("1. 加密\n");
    printf("2. 解密\n");
    scanf("%d", &choice);

    // 获取文件名和密钥
    printf("请输入输入文件名:\n");
    scanf("%s", input_file);

    printf("请输入输出文件名:\n");
    scanf("%s", output_file);

    printf("请输入密钥:\n");
    scanf("%s", key);

    // 根据用户选择执行相应的操作
    switch (choice)
    {
    case 1:
        encrypt(input_file, output_file, key);
        break;
    case 2:
        decrypt(input_file, output_file, key);
        break;
    default:
        printf("无效的选择\n");
        break;
    }

    // 输出加密后的结果和密钥
    printf("密钥为:%s\n", key);
    printf("加密后的结果为:\n");
    print_file(output_file);

    return 0;
}

// 加密函数
void encrypt(char* input_file, char* output_file, char* key)
{
    FILE* fin, * fout;
    int key_len = strlen(key), i = 0;
    char ch;

    fin = fopen(input_file, "r");
    fout = fopen(output_file, "w");

    // 读取输入文件并加密
    while ((ch = fgetc(fin)) != EOF)
    {
        if (ch >= 'a' && ch <= 'z')
        {
            ch = ((ch - 'a') + (key[i % key_len] - 'a')) % 26 + 'a';
            i++;
        }
        else if (ch >= 'A' && ch <= 'Z')
        {
            ch = ((ch - 'A') + (key[i % key_len] - 'a')) % 26 + 'A';
            i++;
        }
        fputc(ch, fout);
    }

    fclose(fin);
    fclose(fout);
}

// 解密函数
void decrypt(char* input_file, char* output_file, char* key)
{
    FILE* fin, * fout;
    int key_len = strlen(key), i = 0;
    char ch;

    fin = fopen(input_file, "r");
    fout = fopen(output_file, "w");

    // 读取输入文件并解密
    while ((ch = fgetc(fin)) != EOF)
    {
        if (ch >= 'a' && ch <= 'z')
        {
            ch = ((ch - 'a') - (key[i % key_len] - 'a') + 26) % 26 + 'a';
            i++;
        }
        else if (ch >= 'A' && ch <= 'Z')
        {
            ch = ((ch - 'A') - (key[i % key_len] - 'a') + 26) % 26 + 'A';
            i++;
        }
        fputc(ch, fout);
    }

    fclose(fin);
    fclose(fout);
}
// 输出文件内容
void print_file(char* filename)
{
    FILE* fin;
    char ch;
    fin = fopen(filename, "r");

    while ((ch = fgetc(fin)) != EOF)
    {
        putchar(ch);
    }

    fclose(fin);
}

源程序

维吉尼亚密码加解密

The senventh homework(DES算法)

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>

void print_hex(const char *tag, const unsigned char *data, int len) {
    printf("%s:", tag);
    for (int i = 0; i < len; ++i) {
        printf(" %02x", data[i]);
    }
    printf("\n");
}

void print_binary(const char *tag, const unsigned char *data, int len) {
    printf("%s:", tag);
    for (int i = 0; i < len; ++i) {
        for (int j = 7; j >= 0; --j) {
            printf("%d", (data[i] >> j) & 1);
        }
        printf(" ");
    }
    printf("\n");
}

int main() {
    // 固定密钥,改变明文
    unsigned char key[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
    unsigned char plaintext[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    unsigned char ciphertext1[8], ciphertext2[8];
    DES_key_schedule ks;
    DES_set_key_unchecked(&key, &ks);
    DES_ecb_encrypt(&plaintext, &ciphertext1, &ks, DES_ENCRYPT);
    for (int i = 0; i < 64; ++i) {
        memcpy(&plaintext, &ciphertext1, sizeof(plaintext));
        plaintext[i / 8] ^= 1 << (i % 8);
        DES_ecb_encrypt(&plaintext, &ciphertext2, &ks, DES_ENCRYPT);
        int diff = 0;
        for (int j = 0; j < 8; ++j) {
            if (ciphertext1[j] != ciphertext2[j]) {
                diff += 8 - __builtin_popcount(ciphertext1[j] ^ ciphertext2[j]);
            }
        }
        printf("改变%d位,输出密文位数改变:%d\n", i + 1, diff);
    }

    // 固定明文,改变密钥
    memset(&plaintext, 0, sizeof(plaintext));
    unsigned char key1[8], key2[8];
    memcpy(&key1, &key, sizeof(key));
    DES_set_key_unchecked(&key1, &ks);
    DES_ecb_encrypt(&plaintext, &ciphertext1, &ks, DES_ENCRYPT);
    for (int i = 0; i < 64; ++i) {
        memcpy(&key2, &key1, sizeof(key));
        key2[i / 8] ^= 1 << (i % 8);
        DES_set_key_unchecked(&key2, &ks);
        DES_ecb_encrypt(&plaintext, &ciphertext2, &ks, DES_ENCRYPT);
        int diff = 0;
        for (int j = 0; j < 8; ++j) {
            if (ciphertext1[j] != ciphertext2[j]) {
                diff += 8 - __builtin_popcount(ciphertext1[j] ^ ciphertext2[j]);
            }
        }
        printf("改变%d位,输出密文位数改变:%d\n", i + 1, diff);
    return 0;
}

说明

代码中首先定义了两个辅助函数 print_hex 和 print_binary,分别用于以十六进制和二进制格式打印数据。然后在 main 函数中,定义了固定密钥、改变明文和固定明文、改变密钥的两个场景,分别进行测试。

在第一个场景中,使用 DES_key_schedule 结构体初始化密钥,并使用 DES_ecb_encrypt 函数对固定的明文进行加密,得到输出的密文 ciphertext1。接着,通过循环改变输入的明文的每一位,得到新的密文 ciphertext2,并计算两个密文之间的差异位数,输出结果。

在第二个场景中,先使用相同的明文和固定的密钥 key 进行加密,得到输出的密文 ciphertext1。接着,通过循环改变密钥的每一位,得到新的密钥 key2,并使用 DES_set_key_unchecked 函数重新设置密钥,再使用 DES_ecb_encrypt 函数对相同的明文进行加密,得到新的密文 ciphertext2,并计算两个密文之间的差异位数,输出结果。

The eighth homework(RSA & Hash)

RSA

代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

int gcd(int a, int b) {
    if (b == 0) {
        return a;
    }
    return gcd(b, a % b);
}

int mod_pow(int base, int exponent, int modulus) {
    int result = 1;
    while (exponent > 0) {
        if (exponent % 2 == 1) {
            result = (result * base) % modulus;
        }
        base = (base * base) % modulus;
        exponent = exponent / 2;
    }
    return result;
}

int main() {
    int p, q, n, phi, e, d, message, cipher, decrypted;

    srand(time(0)); // 设置随机种子

    // 生成两个随机素数p和q
    p = rand() % 100 + 1; // 在1~100之间随机生成p
    while (1) {
        int is_prime = 1;
        for (int i = 2; i <= sqrt(p); i++) {
            if (p % i == 0) {
                is_prime = 0;
                break;
            }
        }
        if (is_prime) {
            break;
        }
        p++;
    }
    q = rand() % 100 + 1; // 在1~100之间随机生成q
    while (1) {
        int is_prime = 1;
        for (int i = 2; i <= sqrt(q); i++) {
            if (q % i == 0) {
                is_prime = 0;
                break;
            }
        }
        if (is_prime) {
            break;
        }
        q++;
    }

    // 计算n和phi(n)
    n = p * q;
    phi = (p - 1) * (q - 1);

    // 选择公钥e
    e = 2;
    while (e < phi) {
        if (gcd(e, phi) == 1) {
            break;
        }
        e++;
    }

    // 计算私钥d
    int k = 1;
    while (1) {
        if ((k * phi + 1) % e == 0) {
            d = (k * phi + 1) / e;
            break;
        }
        k++;
    }

    // 加密
    printf("请输入要加密的消息(小于 %d):", n);
    scanf("%d", &message);
    cipher = mod_pow(message, e, n);
    printf("加密后的密文为:%d\n", cipher);

    // 解密
    decrypted = mod_pow(cipher, d, n);
    printf("解密后的消息为:%d\n", decrypted);

    return 0;
}

说明

在这个实现中,我们使用了以下函数:

  • gcd():计算两个数的最大公约数。
  • mod_pow():计算一个数的幂的模数。

在主函数中,我们首先生成了两个随机素数p和q,并计算了n和phi(n)。然后选择公钥e,并计算了私钥d。接下来,我们通过输入一个消息,使用公钥加密该消息,并使用私钥解密该消息。

在加密过程中,我们需要选择一个小于n的整数作为消息,然后计算其e次幂再对n取模。这个结果就是加密后的密文。

在解密过程中,我们需要使用私钥d来计算密文的d次幂再对n取模。这个结果就是解密后的消息。

需要注意的是,在实际使用中,RSA算法需要使用非常大的素数和整数,以确保足够的安全性。这里我们仅使用了较小的素数和整数作为示例,实际使用中需要使用更大的数值。同时,RSA算法的实现还需要考虑一些其他因素,如填充方案等,以确保安全性和实用性。

Hash作业

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

#define MAX_PATH_LENGTH 256
#define HASH_TABLE_SIZE 10007

typedef struct {
    char path[MAX_PATH_LENGTH];
    DWORD hash;
    struct Node* next;
} Node;

Node* hashTable[HASH_TABLE_SIZE];

DWORD calculateHash(const char* filePath) {
    HANDLE fileHandle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fileHandle == INVALID_HANDLE_VALUE) {
        printf("Error opening file: %s\n", filePath);
        return 0;
    }

    DWORD hash = 0;
    BYTE buffer[4096];
    DWORD bytesRead;

    while (ReadFile(fileHandle, buffer, sizeof(buffer), &bytesRead, NULL)) {
        if (bytesRead == 0)
            break;
        
        for (DWORD i = 0; i < bytesRead; i++) {
            hash = ((hash << 5) + hash) ^ buffer[i];
        }
    }

    CloseHandle(fileHandle);

    return hash;
}

void insertNode(const char* filePath, DWORD hash) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    strcpy(newNode->path, filePath);
    newNode->hash = hash;
    newNode->next = NULL;

    int index = hash % HASH_TABLE_SIZE;

    if (hashTable[index] == NULL) {
        hashTable[index] = newNode;
    } else {
        Node* currentNode = hashTable[index];
        while (currentNode->next != NULL) {
            currentNode = currentNode->next;
        }
        currentNode->next = newNode;
    }
}

void findDuplicateFiles() {
    for (int i = 0; i < HASH_TABLE_SIZE; i++) {
        if (hashTable[i] != NULL) {
            Node* currentNode = hashTable[i];
            while (currentNode != NULL) {
                Node* nextNode = currentNode->next;
                Node* duplicateNode = currentNode->next;

                while (duplicateNode != NULL) {
                    if (duplicateNode->hash == currentNode->hash) {
                        // Compare the contents of the files
                        if (strcmp(duplicateNode->path, currentNode->path) != 0) {
                            printf("Duplicate files found:\n");
                            printf("%s\n", duplicateNode->path);
                            printf("%s\n", currentNode->path);
                            printf("\n");
                        }
                    }

                    duplicateNode = duplicateNode->next;
                }

                currentNode = nextNode;
            }
        }
    }
}

int main() {
    // Initialize the hash table
    for (int i = 0; i < HASH_TABLE_SIZE; i++) {
        hashTable[i] = NULL;
    }

    // Directory to scan for duplicate files
    const char* directory = "C:\\Path\\To\\Directory";

    WIN32_FIND_DATA findData;
    HANDLE findHandle = FindFirstFile(directory, &findData);
    if (findHandle == INVALID_HANDLE_VALUE) {
        printf("Error opening directory: %s\n", directory);
        return 1;
    }

    do {
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // Skip directories
            continue;
        }

        char filePath[MAX_PATH_LENGTH];
        sprintf(filePath, "%s\\%s", directory, findData.cFileName);

        DWORD hash = calculateHash(filePath);
        if (hash != 0) {
            insertNode(filePath, hash);
        }
    } while (FindNextFile(findHandle, &findData));

    FindClose(findHandle);

    findDuplicateFiles();

    return 0;
}

说明

在上述代码中,首先定义了一个Node结构体,用于表示哈希表中的节点。节点包含文件路径、哈希值和指向下一个节点的指针。然后定义了一个哈希表hashTable,使用拉链法解决哈希冲突。

calculateHash函数用于计算文件的哈希值。使用了Windows API中的CreateFile和ReadFile函数来读取文件内容,并对内容进行哈希计算。这里使用了简单的哈希算法,每次读取一个字节进行哈希运算,最终得到文件的哈希值。

insertNode函数用于将文件路径和哈希值插入到哈希表中。根据哈希值计算得到插入位置,如果该位置为空,则直接插入节点;否则,遍历链表直到找到合适的插入位置。

findDuplicateFiles函数用于遍历哈希表,查找具有相同哈希值的文件。对于每个哈希值,遍历对应链表的节点,并与后续节点进行比较。如果发现哈希值相同且文件内容不同的节点,说明找到了重复文件。

在main函数中,首先初始化哈希表,然后使用FindFirstFile和FindNextFile函数遍历指定目录下的所有文件。对于每个文件,我们调用calculateHash函数计算哈希值,并使用insertNode函数将路径和哈希值插入到哈希表中。

最后,调用findDuplicateFiles函数查找重复文件并输出结果。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published