本文章同时发布於:
大家好,继上次Week39 - 各种安全性演算法的应用 - 窃听、电子欺骗实作之後,这次要介绍窜改
、抵赖
的实作。
以下实作大量参考Golang RSA encrypt and decrypt example与Golang: aes-256-cbc examples (with iv, blockSize)。
并且全部的范例都在此,请先 clone 下来会较好理解。
还记得Week38 - 「窜改(falsification)是什麽?」章节防范的方法吗?就是
与电子欺骗的解决方法相同,传输人员在资料上产生一笔独一无二的代码供另一端验证
接下来就要利用产生独一无二的代码
来实作,方法有 2 种:
小明
与早餐店阿姨
如果不够信任彼此
,会采用数位签章
,因为采用讯息识别码
的话,小明
把钥匙给早餐店阿姨
,早餐店阿姨
拿去冒名成小明
就不好了,
使用数位签章
加在原本的循序图串起来就会如下:
看看程序码,进入week40/spoofing/signature
的资料夹:
$ cd week40/spoofing/signature
里头有以下档案:
.
├── badGuyKey : 坏人的私钥
├── badGuyKey.pub : 坏人的公钥
├── goodGuykey : 小明的私钥
├── goodGuykey.pub: 小明的公钥
└── main.go : 程序码
key
与key.pub
是透过ssh-keygen
这个软件来产生的,使用以下指令可以产生一组RSA
公私钥:
$ ssh-keygen -t rsa -f <key's name> -m pem
e.g.
$ ssh-keygen -t rsa -f goodGuykey -m pem
输入後会询问是否要设定passphrase
,这是一个安全密码,如果设定了,以後使用此私钥还要输入此安全密码才可使用,以增加安全性,此范例没有设定。
code 的方面主要可以看main
的部分,注解有解释流程,搭配循序图会较好理解:
// 大量参考: https://gist.github.com/mfridman/c0c5ece512f63d429c4589196a1d4242
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
)
// LoadFile load the file to bytes
func LoadFile(path string) []byte {
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
return content
}
// BytesToPrivateKey bytes to private key
func BytesToPrivateKey(priv []byte) *rsa.PrivateKey {
block, _ := pem.Decode(priv)
enc := x509.IsEncryptedPEMBlock(block)
b := block.Bytes
var err error
if enc {
log.Println("is encrypted pem block")
b, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
log.Fatal(err)
}
}
key, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
log.Fatal(err)
}
return key
}
func main() {
// 坏人的私钥
badGuyPrivateKey := BytesToPrivateKey(LoadFile("./badGuyKey"))
// 小明的私钥
goodGuyPrivateKey := BytesToPrivateKey(LoadFile("./goodGuyKey"))
// 小明的公钥,公钥可以透过私要来取得,所以这边就不在载入公钥档案了
goodGuyPublicKey := goodGuyPrivateKey.PublicKey
// 小明用自己的私钥对讯息签章
messageBytes := []byte("小明餐点: 大冰奶")
hash := sha512.New()
hash.Write(messageBytes)
hashed := hash.Sum(nil)
// 小明用自己的私钥签名
signature, err := rsa.SignPKCS1v15(rand.Reader, goodGuyPrivateKey, crypto.SHA512, hashed)
if err != nil {
panic(err)
}
// 小明的资料被坏人拦截,坏人开始伪造小明的讯息
messageBytes = []byte("小明餐点: 大冰红")
hash = sha512.New()
hash.Write(messageBytes)
hashed = hash.Sum(nil)
// 坏人用自己的私钥签名,并非小明的
signature, err = rsa.SignPKCS1v15(rand.Reader, badGuyPrivateKey, crypto.SHA512, hashed)
if err != nil {
panic(err)
}
// 早餐店阿姨取得小明的公钥,利用此公钥验证之後发现不是小明传的讯息
err = rsa.VerifyPKCS1v15(&goodGuyPublicKey, crypto.SHA512, hashed, signature)
if err != nil {
fmt.Println("Two signatures are not the same. Error: ", err)
return
}
}
小明
与早餐店阿姨
如果够信任彼此
,甚至他们可能是同一个系统,那就不必担心早餐店阿姨
拿小明
的钥匙做坏事了,故可采用讯息识别码
,
使用讯息识别码
加在原本的循序图串起来就会如下:
看看程序码,进入week40/falsification/HMAC
的资料夹:
$ cd week40/falsification/HMAC
里头有以下档案:
.
└── main.go : 程序码
code 主要可以看main
的部分,注解有解释流程,搭配循序图会较好理解:
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func hmacSha256(data string, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
sharedSecret := "小明与早餐店阿姨的共同钥匙"
badGuySecret := "坏人的钥匙"
meals := "小明餐点: 大冰红"
// 小明利用与早餐店阿姨共同的钥匙产生HMAC
requestHMAC := hmacSha256(meals, sharedSecret)
// 坏人拦截小明的封包,利用自己的钥匙产生HMAC
requestHMAC := hmacSha256(meals, badGuySecret)
// 早餐店阿姨利用与小明共同的钥匙产生HMAC
trueHMAC := hmacSha256(meals, sharedSecret)
// 早餐店阿姨比对此两个HMAC,发现不同,故此讯息不是小明传送的
if requestHMAC != trueHMAC {
fmt.Println("Two HMACs are not the same.")
return
}
}
还记得上篇文章 - 「抵赖(repudiation)是什麽?」章节防范的方法吗?就是
要求传输人员在资料上产生一笔独一无二的代码供另一端验证
接下来就要利用产生独一无二的代码
来实作,由於在抵赖
的情境中,小明
就是坏人,所以早餐店阿姨
与小明
本来就不够信任彼此
,所以只可用 1 种方法:
使用数位签章
加在原本的循序图串起来就会如下:
看看程序码,进入week40/repudiation/signature
的资料夹:
$ cd week40/repudiation/signature
里头有以下档案:
.
├── goodGuyKey
├── goodGuyKey.pub
├── key
├── key.pub
└── main.go
钥匙都是透过ssh-keygen
产生,可以参考上方窜改(falsification)
章节的讲解,就不赘述。
code 主要可以看main
的部分,注解有解释流程,搭配循序图会较好理解:
// 大量参考: https://gist.github.com/mfridman/c0c5ece512f63d429c4589196a1d4242
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
)
// LoadFile load the file to bytes
func LoadFile(path string) []byte {
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
return content
}
// BytesToPrivateKey bytes to private key
func BytesToPrivateKey(priv []byte) *rsa.PrivateKey {
block, _ := pem.Decode(priv)
enc := x509.IsEncryptedPEMBlock(block)
b := block.Bytes
var err error
if enc {
log.Println("is encrypted pem block")
b, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
log.Fatal(err)
}
}
key, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
log.Fatal(err)
}
return key
}
func main() {
goodGuyPrivateKey := BytesToPrivateKey(LoadFile("./goodGuyKey"))
// 小明的公钥,公钥可以透过私要来取得,所以这边就不在载入公钥档案了
goodGuyPublicKey := goodGuyPrivateKey.PublicKey
// 小明用自己的私钥对讯息签章
messageBytes := []byte("小明餐点: 大冰奶")
hash := sha512.New()
hash.Write(messageBytes)
hashed := hash.Sum(nil)
// 小明用自己的私钥签名
signature, err := rsa.SignPKCS1v15(rand.Reader, goodGuyPrivateKey, crypto.SHA512, hashed)
if err != nil {
panic(err)
}
// 早餐店阿姨取得小明的公钥,验证後发现的确是小明,传送餐点回去给小明
err = rsa.VerifyPKCS1v15(&goodGuyPublicKey, crypto.SHA512, hashed, signature)
if err != nil {
fmt.Println("Two signatures are not the same. Error: ", err)
return
}
fmt.Println("Verify the signature is correct")
// 小明获得餐点,并且吃完後开市赖帐
// 早餐店阿姨说明当初`rsa.VerifyPKCS1v15`利用小明的公钥验证後的确是小明用私钥签章的,故证明小明确实有点过餐
}
<<: [JS] You Don't Know JavaScript [this & Object Prototypes] - Prototypes [下]
>>: 【教练我想写 C#】建啦哪次不建 Web API # Get
Internxt Drive 是世界上最安全的云端储存服务之一,他采用客户端加密与分布布技术,使得所...
《PSYCHO-PASS心灵判官》中第三集监视官常守朱第二次遇到的事件,是「八王子工厂杀人事件」 在...
Web API -- Application Programming Interface for ...
打造自己的 Hook 自 React 16.8 以後, 使用者就可以在 React 中 创建自定义的...
Powershell 的基础内容已经讲解的差不多了,从今天开始,我们将学习通过脚本来自动化执行批量操...