The missing semester of your CS education--安全和密码学

课程结构

01.课程概览与 shell
02.Shell 工具和脚本
03.编辑器 (Vim)
04.数据整理
05.命令行环境
06.版本控制(Git)
07.调试及性能分析
08.元编程
09.安全和密码学
10.大杂烩
11.提问&回答

本文档修改自这里,补充了一些视频中展示但配套文档中未提供的代码,以及一些注释。

安全和密码学

去年的这节课我们从计算机 用户 的角度探讨了增强隐私保护和安全的方法。 今年我们将关注比如散列函数、密钥生成函数、对称/非对称密码体系这些安全和密码学的概念是如何应用于前几节课所学到的工具(Git和SSH)中的。

本课程不能作为计算机系统安全 (6.858) 或者 密码学 (6.857以及6.875)的替代。 如果你不是密码学的专家,请不要试图创造或者修改加密算法。从事和计算机系统安全相关的工作同理。

这节课将对一些基本的概念进行简单(但实用)的说明。 虽然这些说明不足以让你学会如何 设计 安全系统或者加密协议,但我们希望你可以对现在使用的程序和协议有一个大概了解。

(Entropy) 度量了不确定性并可以用来决定密码的强度。

在这里插入图片描述

正如上面的 XKCD 漫画 所描述的, “correcthorsebatterystaple” 这个密码比 “Tr0ub4dor&3” 更安全——可是熵是如何量化安全性的呢?

熵的单位是 比特。对于一个均匀分布的随机离散变量,熵等于 l o g 2 N log_2N log2N(N为所有可能的个数)。 扔一次硬币的熵是1比特。掷一次(六面)骰子的熵大约为2.58比特。

一般我们认为攻击者了解密码的模型(最小长度,最大长度,可能包含的字符种类等),但是不了解某个密码是如何随机选择的—— 比如掷骰子

使用多少比特的熵取决于应用的威胁模型。 上面的XKCD漫画告诉我们,大约40比特的熵足以对抗在线穷举攻击(受限于网络速度和应用认证机制)。 而对于离线穷举攻击(主要受限于计算速度), 一般需要更强的密码 (比如80比特或更多)。

散列函数

密码散列函数 (Cryptographic hash function) 可以将任意大小的数据映射为一个固定大小的输出。除此之外,还有一些其他特性。 一个散列函数的大概规范如下:

hash(value: array<byte>) -> vector<byte, N>  (N对于该函数固定)

SHA-1是Git中使用的一种散列函数, 它可以将任意大小的输入映射为一个160比特(可被40位十六进制数表示)的输出。 下面我们用sha1sum命令来测试SHA1对几个字符串的输出:

$ printf 'hello' | sha1sum
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
$ printf 'hello' | sha1sum
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
$ printf 'Hello' | sha1sum 
f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0

~ $ touch test.txt                                                              
~ $ echo 'hello' > test.txt       
~ $ sha1sum test.txt
f572d396fae9206628714fb2ce00f72e94f2258f  test.txt

抽象地讲,散列函数可以被认为是一个不可逆,且看上去随机(但具确定性)的函数 (这就是散列函数的理想模型)。 一个散列函数拥有以下特性:

  • 确定性:对于不变的输入永远有相同的输出。
  • 不可逆性:对于hash(m) = h,难以通过已知的输出h来计算出原始输入m
  • 目标碰撞抵抗性/弱无碰撞:对于一个给定输入m_1,难以找到m_2 != m_1hash(m_1) = hash(m_2)
  • 碰撞抵抗性/强无碰撞:难以找到一组满足hash(m_1) = hash(m_2)的输入m_1, m_2(该性质严格强于目标碰撞抵抗性)。

注:虽然SHA-1还可以用于特定用途,但它已经不再被认为是一个强密码散列函数。 你可参照密码散列函数的生命周期这个表格了解一些散列函数是何时被发现弱点及破解的。 请注意,针对应用推荐特定的散列函数超出了本课程内容的范畴。 如果选择散列函数对于你的工作非常重要,请先系统学习信息安全及密码学。

密码散列函数的应用


  • Git中的内容寻址存储(Content addressed storage):散列函数是一个宽泛的概念(存在非密码学的散列函数),那么Git为什么要特意使用密码散列函数?
  • 文件的信息摘要(Message digest):像Linux ISO这样的软件可以从非官方的(有时不太可信的)镜像站下载,所以需要设法确认下载的软件和官方一致。 官方网站一般会在(指向镜像站的)下载链接旁边备注安装文件的哈希值。 用户从镜像站下载安装文件后可以对照公布的哈希值来确定安装文件没有被篡改。
  • 承诺机制(Commitment scheme): 假设我希望承诺一个值,但之后再透露它—— 比如在没有一个可信的、双方可见的硬币的情况下在我的脑海中公平的“扔一次硬币”。 我可以选择一个值r = random(),并和你分享它的哈希值h = sha256(r)。 这时你可以开始猜硬币的正反:我们一致同意偶数r代表正面,奇数r代表反面。 你猜完了以后,我告诉你值r的内容,得出胜负。同时你可以使用sha256(r)来检查我分享的哈希值h以确认我没有作弊。

密钥生成函数

密钥生成函数 (Key Derivation Functions) 作为密码散列函数的相关概念,被应用于包括生成固定长度,可以使用在其他密码算法中的密钥等方面。 为了对抗穷举法攻击,密钥生成函数通常较慢。

密钥生成函数的应用


  • 从密码生成可以在其他加密算法中使用的密钥,比如对称加密算法(见下)。
  • 存储登录凭证时不可直接存储明文密码。
    正确的方法是针对每个用户随机生成一个 salt = random(), 并存储盐,以及密钥生成函数对连接了盐的明文密码生成的哈希值KDF(password + salt)
    在验证登录请求时,使用输入的密码连接存储的盐重新计算哈希值KDF(input + salt),并与存储的哈希值对比。
~ $ echo 'hello' > test.md                                                      
~ $ openssl aes-256-cbc -salt -in test.md -out test.enc.md                      
enter AES-256-CBC encryption password:        # 输入一串字符作为密钥key                                  
Verifying - enter AES-256-CBC encryption password:      # 再次输入刚才的密钥                        
*** WARNING : deprecated key derivation used.                                   
Using -iter or -pbkdf2 would be better.   

~ $ cat test.enc.md
Salted__75L62s|Bv%  

~ $ openssl aes-256-cbc -d -in test.enc.md -out test1.md  
enter AES-256-CBC decryption password:  # 输入刚才的密钥
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.

~ $ cat test1.md   
hello 

~ $ cmp test.md test1.md    # 比较这两个文件,是相同的
~ $ echo $?               
0

对称加密

说到加密,可能你会首先想到隐藏明文信息。对称加密使用以下几个方法来实现这个功能:

keygen() -> key  (这是一个随机方法)

encrypt(plaintext: array<byte>, key) -> ciphertext: array<byte>  (输出密文)
decrypt(ciphertext: array<byte>, key) -> plaintext: array<byte>  (输出明文)

加密方法encrypt()输出的密文ciphertext很难在不知道key的情况下得出明文plaintext
解密方法decrypt()有明显的正确性。因为功能要求给定密文及其密钥,解密方法必须输出明文:decrypt(encrypt(m, k), k) = m

AES 是现在常用的一种对称加密系统。

对称加密的应用


  • 加密不信任的云服务上存储的文件。对称加密和密钥生成函数配合起来,就可以使用密码加密文件: 将密码输入密钥生成函数生成密钥 key = KDF(passphrase),然后存储encrypt(file, key)

非对称加密

非对称加密的“非对称”代表在其环境中,使用两个具有不同功能的密钥: 一个是私钥(private key),不向外公布;另一个是公钥(public key),公布公钥不像公布对称加密的共享密钥那样可能影响加密体系的安全性。
非对称加密使用以下几个方法来实现加密/解密(encrypt/decrypt),以及签名/验证(sign/verify):

keygen() -> (public key, private key)  (这是一个随机方法)

encrypt(plaintext: array<byte>, public key) -> array<byte>  (输出密文)
decrypt(ciphertext: array<byte>, private key) -> array<byte>  (输出明文)

sign(message: array<byte>, private key) -> array<byte>  (生成签名)
verify(message: array<byte>, signature: array<byte>, public key) -> bool  (验证签名是否是由和这个公钥相关的私钥生成的)

非对称的加密/解密方法和对称的加密/解密方法有类似的特征。
信息在非对称加密中使用 公钥 加密, 且输出的密文很难在不知道 私钥 的情况下得出明文。
解密方法decrypt()有明显的正确性。 给定密文及私钥,解密方法一定会输出明文: decrypt(encrypt(m, public key), private key) = m

对称加密和非对称加密可以类比为机械锁。 对称加密就好比一个防盗门:只要是有钥匙的人都可以开门或者锁门。 非对称加密好比一个可以拿下来的挂锁。你可以把打开状态的挂锁(公钥)给任何一个人并保留唯一的钥匙(私钥)。这样他们将给你的信息装进盒子里并用这个挂锁锁上以后,只有你可以用保留的钥匙开锁。

签名/验证方法具有和书面签名类似的特征。
在不知道 私钥 的情况下,不管需要签名的信息为何,很难计算出一个可以使 verify(message, signature, public key) 返回为真的签名。
对于使用私钥签名的信息,验证方法验证和私钥相对应的公钥时一定返回为真: verify(message, sign(message, private key), public key) = true

非对称加密的应用


  • PGP电子邮件加密:用户可以将所使用的公钥在线发布,比如:PGP密钥服务器或 Keybase。任何人都可以向他们发送加密的电子邮件。
  • 聊天加密:像 SignalKeybase 使用非对称密钥来建立私密聊天。
  • 软件签名:Git 支持用户对提交(commit)和标签(tag)进行GPG签名。任何人都可以使用软件开发者公布的签名公钥验证下载的已签名软件。

密钥分发


非对称加密面对的主要挑战是,如何分发公钥并对应现实世界中存在的人或组织。

Signal的信任模型是,信任用户第一次使用时给出的身份(trust on first use),同时支持用户线下(out-of-band)、面对面交换公钥(Signal里的safety number)。

PGP使用的是信任网络。简单来说,如果我想加入一个信任网络,则必须让已经在信任网络中的成员对我进行线下验证,比如对比证件。验证无误后,信任网络的成员使用私钥对我的公钥进行签名。这样我就成为了信任网络的一部分。只要我使用签名过的公钥所对应的私钥就可以证明“我是我”。

Keybase主要使用社交网络证明 (social proof),和一些别的精巧设计。

每个信任模型有它们各自的优点:我们(讲师)更倾向于 Keybase 使用的模型。

案例分析

密码管理器


每个人都应该尝试使用密码管理器,比如KeePassXCpass1Password)。

密码管理器会帮助你对每个网站生成随机且复杂(表现为高熵)的密码,并使用你指定的主密码配合密钥生成函数来对称加密它们。

你只需要记住一个复杂的主密码,密码管理器就可以生成很多复杂度高且不会重复使用的密码。密码管理器通过这种方式降低密码被猜出的可能,并减少网站信息泄露后对其他网站密码的威胁。

两步验证(双因子验证)


两步验证(2FA)要求用户同时使用密码(“你知道的信息”)和一个身份验证器(“你拥有的物品”,比如YubiKey)来消除密码泄露或者钓鱼攻击的威胁。

全盘加密


对笔记本电脑的硬盘进行全盘加密是防止因设备丢失而信息泄露的简单且有效方法。 Linux的cryptsetup + LUKS, Windows的BitLocker,或者macOS的FileVault都使用一个由密码保护的对称密钥来加密盘上的所有信息。

聊天加密


SignalKeybase使用非对称加密对用户提供端到端(End-to-end)安全性。

获取联系人的公钥非常关键。为了保证安全性,应使用线下方式验证Signal或者Keybase的用户公钥,或者信任Keybase用户提供的社交网络证明。

SSH


我们在命令行环境-远端机器讨论了SSH和SSH密钥的使用。那么我们今天从密码学的角度来分析一下它们。

当你运行ssh-keygen命令,它会生成一个非对称密钥对:公钥和私钥(public_key, private_key)。 生成过程中使用的随机数由系统提供的熵决定。这些熵可以来源于硬件事件(hardware events)等。 公钥最终会被分发,它可以直接明文存储。 但是为了防止泄露,私钥必须加密存储。ssh-keygen命令会提示用户输入一个密码,并将它输入密钥生成函数 产生一个密钥。最终,ssh-keygen使用对称加密算法和这个密钥加密私钥。

在实际运用中,当服务器已知用户的公钥(存储在.ssh/authorized_keys文件中,一般在用户HOME目录下),尝试连接的客户端可以使用非对称签名来证明用户的身份——这便是挑战应答方式。 简单来说,服务器选择一个随机数字发送给客户端。客户端使用用户私钥对这个数字信息签名后返回服务器。 服务器随后使用.ssh/authorized_keys文件中存储的用户公钥来验证返回的信息是否由所对应的私钥所签名。这种验证方式可以有效证明试图登录的用户持有所需的私钥。

资源

课后练习

    1. 假设一个密码是由四个小写的单词拼接组成,每个单词都是从一个含有10万单词的字典中随机选择,且每个单词选中的概率相同。 一个符合这样构造的例子是correcthorsebatterystaple。这个密码有多少比特的熵?
    2. 假设另一个密码是用八个随机的大小写字母或数字组成。一个符合这样构造的例子是rg8Ql34g。这个密码又有多少比特的熵?
    3. 哪一个密码更强?
    4. 假设一个攻击者每秒可以尝试1万个密码,这个攻击者需要多久可以分别破解上述两个密码?
  1. 密码散列函数Debian镜像站下载一个光盘映像(比如这个来自阿根廷镜像站的映像)。使用sha256sum命令对比下载映像的哈希值和官方Debian站公布的哈希值。如果你下载了上面的映像,官方公布的哈希值可以参考这个文件
  2. 对称加密 使用 OpenSSL的AES模式加密一个文件: openssl aes-256-cbc -salt -in {源文件名} -out {加密文件名}。 使用cat或者hexdump对比源文件和加密的文件,再用 openssl aes-256-cbc -d -in {加密文件名} -out {解密文件名} 命令解密刚刚加密的文件。最后使用cmp命令确认源文件和解密后的文件内容相同。
  3. 非对称加密
    1. 在你自己的电脑上使用更安全的ED25519算法生成一组SSH 密钥对。为了确保私钥不使用时的安全,一定使用密码加密你的私钥。
    2. 配置GPG
    3. 给Anish发送一封加密的电子邮件(Anish的公钥)。
    4. 使用git commit -S命令签名一个Git提交,并使用git show --show-signature命令验证这个提交的签名。或者,使用git tag -s命令签名一个Git标签,并使用git tag -v命令验证标签的签名。

习题解答

  1. a. 假设一个密码是从四个小写的单词拼接组成,每个单词都是从一个含有10万单词的字典中随机选择,且每个单词选中的概率相同。 一个符合这样构造的例子是 correcthorsebatterystaple 。这个密码有多少比特的熵?

    • l o g 2 ( 100 , 00 0 4 ) = 20 l o g 2 ( 10 ) = 66 b i t log_2(100,000^4)=20log_2(10)=66 bit log2(100,0004)=20log2(10)=66bit

    b. 假设另一个密码是用八个随机的大小写字母或数字组成。一个符合这样构造的例子是 rg8Ql34g 。这个密码又有多少比特的熵?

    • l o g 2 ( 6 2 8 ) = 8 l o g 2 ( 62 ) = 48 log_2(62^8)=8log_2(62)=48 log2(628)=8log2(62)=48

    c. 从上面的计算结果,第一个密码的熵更大,因此更强。

    d. 假设一个攻击者每秒可以尝试1万个密码,这个攻击者需要多久可以分别破解上述两个密码?

    • 因为每个密码的概率是相同,所以平均而言,需要的破解时间约为尝试所有可能密码所花时间的一半(概率论期望值的简单应用,记所有可能密码个数为x,每年尝试的密码数为y,破解所需的平均时间为: 1 x ⋅ y ( 1 + 2 + ⋯ + x ) = 1 x × ( 1 + x ) × x / 2 y = 1 2 × 1 + x y \frac{1}{x\cdot y}(1+2+\cdots +x)=\frac{1}{x}\times \frac{(1+x)\times x/2}{y}=\frac{1}{2}\times\frac{1+x}{y} xy1(1+2++x)=x1×y(1+x)×x/2=21×y1+x
    • 对于第一个密码: 100 , 00 0 4 / 1 0 4 / ( 365 × 24 × 3600 ) / 2 = 1.085 亿年 100,000^4/10^4/(365\times 24\times 3600)/2=1.085亿年 100,0004/104/(365×24×3600)/2=1.085亿年
    • 对于第二个密码: 6 2 8 / 1 0 4 / ( 365 × 24 × 3600 ) / 2 = 346 年 62^8/10^4/(365\times 24\times 3600)/2=346年 628/104/(365×24×3600)/2=346
  2. 密码散列函数Debian镜像站下载一个光盘映像(比如这个来自阿根廷镜像站的映像)。使用sha256sum命令对比下载映像的哈希值和官方Debian站公布的哈希值。如果你下载了上面的映像,官方公布的哈希值可以参考这个文件

  • 使用国内的阿里云镜像源,注意下载目录为/debian-cd/11.7.0/amd64/iso-cd/,根据版本更新,一般只需变动该目录中的版本号,然后,根据你的系统选择对应版本的iso文件下载
  • 接下来进行哈希值比对:
    ~/下载 $ curl https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS\
        | grep debian-11.7.0-amd64-netinst.iso
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                    Dload  Upload   Total   Spent    Left  Speed
    100   302  100   302    0     0    253      0  0:00:01  0:00:01 --:--:--   254
    eb3f96fd607e4b67e80f4fc15670feb7d9db5be50f4ca8d0bf07008cb025766b  debian-11.7.0-amd64-netinst.iso
    
    ~/下载 $ sha256sum debian-11.7.0-amd64-netinst.iso
    eb3f96fd607e4b67e80f4fc15670feb7d9db5be50f4ca8d0bf07008cb025766b  debian-11.7.0-amd64-netinst.iso
    
  • 哈希值比对一致,说明从阿里云镜像源下载的文件就是官方的版本。
  1. 对称加密 使用 OpenSSL的AES模式加密一个文件: openssl aes-256-cbc -salt -in {源文件名} -out {加密文件名}。 使用cat或者hexdump对比源文件和加密的文件,再用 openssl aes-256-cbc -d -in {加密文件名} -out {解密文件名} 命令解密刚刚加密的文件。最后使用cmp命令确认源文件和解密后的文件内容相同。
  • 见上面对称加密的小节,已经给出该例子
  1. 非对称加密

    1.在你自己的电脑上使用更安全的 ED25519 算法生成一组 SSH 密钥对。为了确保私钥不使用时的安全,一定使用密码加密你的私钥。

    • 参考前面的命令行环境一讲
    ~ $ ssh-keygen -o -a 100 -t ed25519
    Generating public/private ed25519 key pair.
    # 输入key即将保存到的文件名
    Enter file in which to save the key (/home/laihj/.ssh/id_ed25519): id_ed25519
    
    # 为SSH产生的私钥设置密码
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    # 使用该私钥ssh到远端服务器时,终端会提示输入私钥密码
    
    ~ $ ls ~/.ssh
    config id_ed25519     id_ed25519.pub known_hosts
    

    2.配置GPG,更详细的配置可以参考用更现代的方法使用PGP

    • 使用gpg生成密钥(gpg --full-gen-key会有更详细的配置参数过程)
    ~ $ sudo apt install gnupg
    ~ $ gpg --gen-key
    gpg: agent_genkey failed: 没有那个文件或目录
    # 如果你之前执行过这个命令并删除了~/.gnupg目录,会出现这条错误提示
    # 需要重启gpg-agent服务
    ~ $ gpgconf --kill gpg-agent
    
    ~ $ gpg --gen-key
    # 提示输入的姓名、邮箱需要与~/.gitconfig文件中录入的一致,否则执行git为一份提交签名时会报错
    # 之后,还会弹出窗口,要求为私钥设置密码
    [Lines Omitted]
    pub   rsa3072 2023-05-12 [SC] [有效至:2025-05-11]
          07C700F1B0F8A6BFDA61571CA29FF423FCBD1279
    uid                      usrname <usrname@example.com>
    sub   rsa3072 2023-05-12 [E] [有效至:2025-05-11]
    
    • 完成后,公钥、私钥存储在~/.gnupg/pubring.kbx中,查看方式如下(pub代表公钥,sec代表私钥)
    ~ $ gpg --list-keys
    /home/laihj/.gnupg/pubring.kbx
    ------------------------------
    pub   rsa3072 2023-05-12 [SC] [有效至:2025-05-11]
          07C700F1B0F8A6BFDA61571CA29FF423FCBD1279
    uid             [ 绝对 ] usrname <usrname@example.com>
    sub   rsa3072 2023-05-12 [E] [有效至:2025-05-11]
    
    ~ $ gpg --list-secret-keys
    # 或者使用:gpg -K
    /home/laihj/.gnupg/pubring.kbx
    ------------------------------
    sec   rsa3072 2023-05-12 [SC] [有效至:2025-05-11]
          07C700F1B0F8A6BFDA61571CA29FF423FCBD1279
    uid             [ 绝对 ] usrname <usrname@example.com>
    ssb   rsa3072 2023-05-12 [E] [有效至:2025-05-11]
    
    • 最好同时创建一份吊销证书,在你发现密钥泄漏或其他安全风险时,及时废止这份密钥。
    ~ $ gpg --output ~/revocation.crt --gen-revoke usrname@example.com
    # 根据提示选择吊销原因,输入描述(这条信息在你执行吊销的时候,能被其他使用者看到)
    
    ~ $ chmod 600 revocation.crt
    # 设置权限,避免其他人能使用这份吊销证书,同时将该文件保存到安全隐蔽的地方
    

    3.给Anish发送一封加密的电子邮件(Anish的公钥):

    • 导入Anish发布的公钥,并完成验证
    ~ $ curl https://keybase.io/anish/pgp_keys.asc | gpg --import   
    
    ~ $ gpg --list-keys
    # ~/.gnupg/pubring.kbx中除了刚才创建的自己的公钥,还存入了Anish的公钥
    
    ~ $ gpg --edit-key "Anish Athalye"  # 进入gpg控制台
    gpg> fpr
    pub   rsa4096/C3F6E4F5086B3B32 2014-10-30 Anish Athalye <me@anishathalye.com>
    主密钥指纹: 72EE 4824 FA6E FF1F E750  A015 C3F6 E4F5 086B 3B32
    # 将这个密钥指纹与Anish发布在网站上的做匹配,一致
    
    • 接下来,使用Anish的公钥加密信息
    ~ $ touch message.txt
    ~ $ echo 'hello' > message.txt
    ~ $ gpg --encrypt --sign --armor -r me@anishathalye.com message.txt
    # 在本目录下会生成一个message.txt.asc的加密文件
    # 这个文件,只有拥有私钥的Anish能解密
    
    # 如果你也想查看这个加密文件,需要使用:
    ~ $ gpg --encrypt --sign --armor -r me@anishathalye.com -r usrname@example.com message.txt   
    # 添加第二个 -r 接收人,你自己就能解密这个文件
    ~ $ gpg message.txt.asc  
    
    • 接下来,你就可以尝试用邮件或其他方式,将这个使用Anish的公钥加密的文件发送给他(这里只是做说明,不推荐发送无意义的信息!)

    4.使用git commit -S命令签名一个Git提交,并使用git show --show-signature命令验证这个提交的签名。或者,使用git tag -s命令签名一个Git标签,并使用git tag -v命令验证标签的签名。

    • 创建一个新的仓库,使用gpg为Git提交签名
    ~ $ mkdir -p signgit; cd signgit
    ~/signgit $ git init
    Initialized empty Git repository in /home/laihj/signgit/.git/
    ~/signgit (main) $ touch hello.txt
    ~/signgit (main?) $ echo "hello" > hello.txt
    ~/signgit (main?) $ git add hello.txt
    ~/signgit (main+) $ git commit -S -m "Sign a commit"
    [main (root-commit) 03fa307] Sign a commit
    1 file changed, 1 insertion(+)
    create mode 100644 hello.txt
    
    • 显示提交的签名
    ~/signgit (main) $ git show --show-signature
    commit 03fa307f9ced5d9717473a429d76122e46c7a70f (HEAD -> main)
    gpg: Signature made Fri May 12 17:05:28 2023 CST
    gpg:                using RSA key 07C700F1B0F8A6BFDA61571CA29FF423FCBD1279
    gpg:                issuer "usrname@example.com"
    gpg: checking the trustdb
    gpg: marginals needed: 3  completes needed: 1  trust model: pgp
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    gpg: next trustdb check due at 2025-05-11
    gpg: Good signature from "usrname <usrname@example.com>" [ultimate]
    Author: usrname <usrname@example.com>
    Date:   Fri May 12 17:05:28 2023 +0800
    
        Sign a commit
    
    diff --git a/hello.txt b/hello.txt
    new file mode 100644
    index 0000000..ce01362
    --- /dev/null
    +++ b/hello.txt
    @@ -0,0 +1 @@
    +hello
    
    • 创建一个带签名的标签,并验证
    ~/signgit (main) $ git tag -s "v0.0.0" -m "Create a tag"
    
    ~/signgit (main) $ git tag -v v0.0.0
    object 03fa307f9ced5d9717473a429d76122e46c7a70f
    type commit
    tag v0.0.0
    tagger usrname <usrname@example.com> 1683883065 +0800
    
    Create a tag
    gpg: Signature made Fri May 12 17:18:13 2023 CST
    gpg:                using RSA key 07C700F1B0F8A6BFDA61571CA29FF423FCBD1279
    gpg:                issuer "usrname@example.com"
    gpg: Good signature from "usrname <usrname@example.com>" [ultimate]
    
    • 执行 git commit -S 提交时,可能会出现下面的错误(主要原因是gpg的id信息与git中录入的不一致,或者gpg密钥过期等)
    error: gpg failed to sign the data
    fatal: failed to write commit object
    

    这个问题网上有一些解决方案可供参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值