本文介绍: 头歌—密码学基础

第1关:哈希函数

题目

任务描述

本关任务利用哈希算法统计个字符出现个数

相关知识

为了完成本任务,你需要掌握:1.密码学哈希函数概念特性,2.安全哈希算法

密码学哈希函数概念特性

我们需要理解第一个密码学基础知识密码学哈希函数,哈希函数一个数学函数具有以下三个特性: ● 其输入可为任意大小字符串。 ● 它产生固定大小输出。为使本章讨论更具体,我们假设输出大小256位,但是,我们讨论用于任意规模的输出,只要其足够大。 ● 它能进行有效计算简单来说就是对于特定的输入字符串,在合理时间内,我们可以算出哈希函数输出。更准确地说,对应n位的字符串,其哈希值计算复杂度O(n)。 这些特性定义了一般哈希函数,以这个函数为基础,我们可以创建数据结构例如哈希表。我们将只专注于加密的哈希函数,要使哈希函数达到密码安全,我们要求其具有以下三个附加特性:

  1. 碰撞阻力(collisionresistance
  2. 隐秘性(hiding
  3. 谜题友好(puzzlefriendliness

下面具体阐述这三个特性

安全哈希算法

安全哈希算法(SecureHashAlgorithm256,简称SHA−256)。哈希函数有很多,但SHA−256是一个主要被比特币世界采用,并且效果还很不错的哈希函数。 回想一下,我们要求哈希函数可以用于任意长度输入。幸运的是,只要我们能建立一个用于固定长度输入的哈希函数,然后通过一般方法,就可以将接受固定长度的哈希函数转化为可接受任意长度输入的哈希函数,我们称这个转换过程MDMerkle−Damgard变换SHA−256采用这种变换方法常用哈希函数之一。在通用术语中,这种基础型,可用于固定长度,具备碰撞阻力的哈希函数被称为压缩函数(compressionfunction)。经过验证,如果基本压缩函数具有碰撞阻力的特性,那么经过转换生成的哈希函数也具有碰撞阻力。 MD变换很简单。比如压缩函数代入长度m的输入值,并产生长度短一些为n的输出值。哈希函数的输入(可为任意大小)被分为长度m−n区块MD变换运作过程如下:将每个区块与之前区块的输出一起代入压缩函数,注意,输入长度则变为(m−n)+n=m,也刚好就是压缩函数的输入长度。对于第一个区块而言,之前没有的区块,我们需要选取一个初始向量。每次调用哈希函数,这个数字都会被再一次使用,而在实践中,你可以直接标准文档中找到它。最后一个区块的输出也就是返回的结果。 SHA−256函数利用了这样的一个压缩函数,这个压缩函数把一个768位的输入压缩成一个256位的输出,每一个区块大小512位。

编程要求

根据提示,在右侧编辑器补充代码,输出每个字符串的次数,具体格式样例,输出按照字符串的字典从小到大输出。

测试说明

平台会对你编写代码进行测试:

测试输入:

 5 a ab abc a ab

预期输出:

 a 2 ab 2 abc 1

提示: 可以使用map<string,int>

代码

map统计一下每个字符出现次数即可

#include<bits/stdc++.h>
using namespace std;
//在下面Begin和End之间补全代码
/*********** Begin ***********/
int main()
{
    int n;
    cin>>n;
    string x;
	map<string, int> mp;
    for(int i=0; i<n; i++)
    {
        cin>>x;
        auto it = mp.find(x);
        if (it != mp.end()) { // 键存在
        	mp[x] = mp[x] + 1;
		} else {
			mp[x] = 1;
		}
    }
    
    for (auto i : mp) {
    	cout << i.first << " " << i.second << endl;
	}
    return 0;
}
/*********** End ***********/

第2关:数字签名

题目

任务描述

本关任务:对给定身份以及消息进行数字签名

相关知识

为了完成本关任务,你需要掌握:1.数字签名概念和性质,2.公钥身份

数字签名概念和性质

数字签名密码学中的第二个重要部分数字签名被认为是对纸上手写签名数字模拟。我们对数字签名有两个特性要求,使其与我们对手写签名的预期一致。

  • 第一,只有你可以制作自己的签名,但任何看到它的人都可以验证其有效性;
  • 第二,我们希望签名只与某一特定文件发生联系,因此该签名不能用于表明你同意或支持另一份不同的文件。

对于手写签名来说,第二条就如同确保别人不能将你的签名从一份文件上剪下来,贴到另一份文件的末尾那样。 那我们如何通过密码学来构建这些性质呢?首先,让我们把之前的直观讨论说得更具体一些,以便今后可以更好地论证数字签名方案,并讨论安全特性。 数字签名方案

(1)数字签名方案由以下三个算法构成: ● (sk,pk):=generateKeys(keysize)``generateKeys方法keysize作为输入,来产生一对公钥私钥私钥sk安全保存,并用来签名一段消息公钥pk是人人都可以找到的,拿到它,就可以用来验证你的签名。 ● sig:=sign(sk,message) 签名过程是把一段消息私钥作为一个输入,对于消息输出是签名。 ●isValid:=verify(pk,message,sig) 验证过程是通过把一段消息和签名消息公钥作为输入,如果返回的结果是真,证明签名属实;如果返回的结果为假,证明签名消息为假。 (2)我们要求以下两个性质有效: ● 有效签名可以通过验证,即: verify(pk,message,sign(sk,message))==true ● 签名不可伪造。

公钥身份

让我们来看一下与数字签名并行的一个有用技巧基本想法是从数字签名模式中拿出一个公共验证密钥,并将其与一个人或一个系统参与者的身份对等。如果你见到一条消息的签名被公钥pk正确验证,那么你可以认为pk就是在表达这条消息。你真的可以将公钥认为是参与者或者系统的一方,他可以通过签署声明发布声明。从这个角度来说,公钥就是身份,让某人能为pk身份发声,他必须知道相应的密钥sk。 将公钥视为身份的一个结果是,你可以随时制定新的身份——你可以简单通过数字签名方案中的generateKeys程序生成新的密钥skpkpk是你可以使用的新的公共身份,sk是相应的密钥,只有你自己知道并可以让你代表身份为pk发声。在实践中,你可能使用pk的哈希作为你的身份,这是因为公钥很大。如果是这样的话,为了验证消息来自你的身份,人们会需要验证:

  • (1)你的身份确实是pk的哈希;
  • (2)信息能经过公钥pk验证。

此外,在默认情况下,你的公钥pk基本上看起来是随机的,也并没有人能够通过检查pk发现你的现实身份(当然,一旦你开始使用这个身份发表声明,这些声明可能泄露信息,而让别人将你的真实身份与pk联系起来。我们很快会更详细讨论这个问题)。你可以生成一个看起来随机的新身份,看起来像人群中的一张脸,但这些都只有你能够控制

编程要求

根据提示,在右侧编辑器补充代码,根据公钥即身份,我们可以模拟一次消息签名,假如你的身份是e,有哈希函数H(x)=ax+b,那么我们可以把pk=H(e)作为公钥,sk=H(e)−1modq作为私钥,我们用私钥对消息m进行加密,即en(m)=sk∗m,那么我们解密就可以这样计算de(en(m))=en(m)∗pk这里q保证是素数。 输入

 e a b q m

输出

 pk sk en(m)

输入

 3 4 5 11 6

输出

17212

提示: 费马定理逆元,可以查询一下。

代码

ksm逆元

b 与 p 互质情况下,若 a/b ≡ a*x (mod p),则 x 为 b乘法逆元

可转化为 b * x ≡ 1 (mod p)

费马定理:若 p 为质数,得:bp-1 ≡ 1 (mod p)

又有:b * x ≡ 1 (mod p)

得到:b * bp-2 ≡ 1 (mod p),所以 x = bp-2

// 题目规定 p 是质数,我们使用费马定理需要 a p 是互质并且 p 是质数
// 只有 a 是 p 得倍数时,不互质

if (a % p == 0) System.out.println("impossible");
else System.out.println(quick_power(a, p - 2, p));

// 快速
private static long quick_power(long a, long k, long p) {
    long ans = 1;
    while (k > 0) {
        if ((k &amp; 1) == 1) ans = ans * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return ans;
}
#include<bits/stdc++.h>
using namespace std;
int e,a,b,q,m;

// 快速幂求逆元
long ksm(long a, long k, long p) {
    long ans = 1;
    while (k > 0) {
        if ((k &amp; 1) == 1) ans = ans * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return ans;
}

// 哈希函数
int H(int x) {
    return a * x + b;
}

// 公钥
int pk() {
    return H(e);
}

// 私钥
int sk() {
    return ksm(H(e), q-2, q);
}

// 加密
int en() {
    return sk() * m;
}

int main()
{
    cin>>e>>a>>b>>q>>m;
    cout << pk() << endl;
    cout << sk() << endl;
    cout << en() << endl;
    return 0;
}

原文地址:https://blog.csdn.net/Changersh/article/details/134778036

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_38176.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注