我正在试着写一些不安全的东西。这样做的目的是加密服务器端的mp3s,这样它们就不能只通过wget或“另存为”下载,并被普通用户使用。
其思想是在服务器端,加载mp3,aes-cfb对其加密,在报头中发送密钥,在响应体中发送加密的mp3。
服务器端使用Go的stdlib和AES-CFB加密。首先使用base64编码,然后是加密的[]byte-s的普通输出。
在客户端,我使用伪造来解密。我发送了一个xhr,读取arraybuffer,使用forge解密,并将输出写入控制台。
test.txt的内容是“这只是一个测试,它可能工作,也可能不工作。”
main.go
package main
import (
"net/http"
"io"
"crypto/rand"
"os"
"crypto/aes"
"crypto/cipher"
"fmt"
)
var (
key = "1234567890123456"
fn = "test.txt"
)
func main() {
http.Handle("/file/", http.HandlerFunc(serveFile))
http.Handle("/", http.FileServer(http.Dir("public")))
http.ListenAndServe(":8080", nil)
}
func serveFile(w http.ResponseWriter, r *http.Request) {
file, e := os.Open(fn)
if e != nil {
fmt.Println(e.Error())
return
}
defer file.Close()
fi, _ := file.Stat()
b := make([]byte, fi.Size())
io.ReadFull(file, b)
o := AESencrypt([]byte(key), b)
w.Header().Set("Access-Control-Allow-Origin", "*")
//w.Header().Set("Key", key)
fmt.Println(o)
fmt.Println(len(o))
w.Write(o)
}
func AESencrypt(key []byte, content []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize + len(content))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], content)
return ciphertext
}index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MP3 Player Demo</title>
</head>
<body>
<button onclick="loadFile('1')">Load</button>
<script src="node_modules/node-forge/js/forge.bundle.js"></script>
<script src="assets/reader.js"></script>
</body>
</html>reader.js
function loadFile(filename) {
//var context = new AudioContext || new webkitAudioContext();
var request = new XMLHttpRequest();
var url = "http://localhost:8080/file/";
request.open("GET", url + filename, true);
request.responseType = "arraybuffer";
request.onload = function () {
var rt = request.response;
console.log(rt);
var decipher = forge.cipher.createDecipher('AES-CFB', forge.util.createBuffer('1234567890123456'));
decipher.start({iv: forge.util.createBuffer('1234567890123456')});
decipher.update(forge.util.createBuffer(rt));
decipher.finish();
console.log(decipher.output);
console.log(decipher.output.bytes());
console.log('--------------');
};
request.send();
}结果很奇怪。
它是“正确”解密的,但是每个解密结果都有一个随机长度的前缀或垃圾。
3输出:
ArrayBuffer { byteLength: 69 } reader.js:10:9
Object { data: "3~æÿK¥=®ªÿÂßthis is just a test…", read: 0, _constructedStringLength: 69 } reader.js:16:9
3~æÿK¥=®ªÿÂßthis is just a test and maybe it's working maybe not. reader.js:17:9
-------------- reader.js:18:9
ArrayBuffer { byteLength: 69 } reader.js:10:9
Object { data: "ÅJÇ9Ë54«ÚV«this is just a test…", read: 0, _constructedStringLength: 69 } reader.js:16:9
ÅJÇ9Ë54«ÚV«this is just a test and maybe it's working maybe not. reader.js:17:9
-------------- reader.js:18:9
ArrayBuffer { byteLength: 69 } reader.js:10:9
Object { data: "ªÕxïÂ`zqA \cýx#this is just a test…", read: 0, _constructedStringLength: 69 } reader.js:16:9
ªÕxïÂ`zqA \cýx#this is just a test and maybe it's working maybe not. reader.js:17:9
-------------- reader.js:18:9这里的输出被截断了,但它与test.txt是一样的。正如你所看到的,它总是以随机垃圾作为前缀。
我做错了什么?AES-CFB的伪造实现是错误的还是Go的?为什么它们是不兼容的?或者为什么解密会有所不同?如果AES-CFB是一个标准,为什么会有不同的实现?
我也尝试了gopherjs作为替代方案,它工作得很好,但a)代码太大(约3.7mb),b)我不知道如何使用gopherjs播放解密的音频。但这只是一个次要问题。
发布于 2017-01-07 22:34:49
你忘了拿掉静脉输液器,这意味着输液器也被“解密”了,结果就是胡说八道。
这种胡言乱语似乎被解释为UTF-8,其中一个字符可能具有多字节编码,因此您打印出的IV的大小可能略有不同。
因此,删除IV,并在调试二进制值时尝试打印出十六进制。
https://stackoverflow.com/questions/41521671
复制相似问题