2017-07-31 81 views
1

我试图加密动态QRCode的数据净荷。加密输入长度与输出长度相同的QRCode净荷

我们有一个从动态数据生成QRCode的应用程序,如果需要,我们希望有一个选项来加密有效负载。

由于QRCodes固有的尺寸限制,的要求之一是,有效载荷数据的大小必须为加密数据相同。如果加密数据不同/太大,QRCode可能无法正确扫描/解码。

我试图在CTR模式下使用AES加密(流而不是块),如其他地方所建议的。结果是输出密码字节与输入字节大小相同,但是将字节转换为字符友好格式(例如base64)会产生比原始有效负载长得多的字符串长度。

有没有办法加密一个字符串,使纯文本和加密的字符串长度是相同的?

根据这里的MIT pdf,https://courses.csail.mit.edu/6.857/2014/files/12-peng-sanabria-wu-zhu-qr-codes.pdf,他们提到了已经存在的解决方案,他们称之为SEQR(对称加密QR)代码。但是,我仍然没有找到一个解决方案,正如文章中提到的那样,该解决方案生成的加密输出与纯文本输入的长度相同。

我们在后端使用C#.NET,ZXing QRCode库和我们前端的Javascript,使用CryptoJS。

我还创建了一个JSFiddle,在CTR模式下展示了AES。

http://jsfiddle.net/s1jeweja/5/

var options = { mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding }; 

/*** encrypt */ 
var json = CryptoJS.AES.encrypt("some plain text", "secret", options); 
var ciphertext = json.ciphertext.toString(CryptoJS.enc.UTF8); 
document.getElementById("id2").innerHTML = ciphertext; 
//debugger; 
/*** decrypt */ 
var decrypted = CryptoJS.AES.decrypt(json, "secret", options); 
var plaintext = decrypted.toString(CryptoJS.enc.Utf8); 



document.getElementById("decrypt").innerHTML = plaintext; // text can be a random lenght 
+0

QR码没有携带原始二进制数据的困难,因此对于“CHAR友好的”有效载荷的要求似乎武断和适得其反。我也认为你应该考虑是否真的安全地加密了与明文完全相同大小的有效载荷。例如,你的系统是否容易受到[重放攻击](https://en.wikipedia.org/wiki/Replay_attack)的影响? –

+0

我的印象是,将有效载荷存储为二进制不是一种选择,我会重新考虑这一点。 你是对的漏洞风险。背景:我们正在将个人信息存储在QRCode中并将其打印为一个事件。它更多的是阻止其他参与者在未经他们许可的情况下收集参与者信息。如果有人以某种方式收集所有与会者的实体QRCodes并利用漏洞,我会认为将有更简单的方法来收集这类信息?我认为这是一个可以接受的风险 – gorillapower

回答

1

你正在寻找一个Format Preserving Encryption其中明文转换成文本字符密文到文本字符。其中一种方法是改编经典Vigenère cipher。生成范围为0..25的伪随机数密钥流,并使用它们对字母表中的明文字符进行循环移位。

您已经在使用AES-CTR,因此请使用它来生成密钥流。屏蔽密钥流的五位。如果这五位在0..25中,则使用它们将下一个明文字符循环移位到相应的密文字符。如果五位在26..31的范围内,则丢弃它们并获得另外五位。

伪代码,这看起来是这样的:

textToTextEncode(plaintext) 
    for each character p in plaintext 
    c <- p + getNextShift() 
    if c > 'z' 
     c <- c - 26 
    end if 
    write(c, cyphertextFile) 
    end for 
end textToTextEncode() 

getNextShift() 
    repeat 
    b <- getNextByte(AES-CTR) 
    b <- b & 0b00011111 // Binary mask. 
    until b < 26 
    return b 
end getNextShift() 

对于解密,你需要减去位移值,并添加26如果结果低于“A”。

ETA:正如你从下面的评论中可以看到的,你将需要一个对每个QRCode唯一的随机数(AKA IV)。在每个QRCode的开始或结尾处为nonce预留固定数量的字节。不要加密这些字节,你必须保持清晰。从完整的QRCode中提取它们并使用它们初始化AES-CTR方法。然后使用该AES-CTR解密该QRCode的其余部分。更多的字节,最多16个,您将拥有更多的安全性。

+0

这根本不安全。假设唐纳德特朗普出席活动并收到一个QR码,他的名字被加密为“TKRREB NZIBP”。然后他可以直接从这些信息中提取密钥流,并可以用它来解密任何其他名字,例如'RWVRVI IJOBA =巴拉克奥巴马。 –

+0

AES-CTR需要一个随机数来确保安全性。提问者提供的代码的'选项'参数的一部分。总是有关于安全加密的附加信息:密钥,IV /随机数等。 – rossum

+0

是的,但是OP请求密文与明文大小相同,所以没有任何IV或随机数。 –

1

据我所知,输入类型必须是字符串的限制或多或少是历史性的,并且在过去从未改变过。不管用不同的条形码格式来编码字节数据的可能性。

这里是一个小的代码片断这对我的作品:

[Test] 
    public void Test_Binary_Data_Encoding_As_Char() 
    { 
    var writer = new BarcodeWriter 
    { 
     Format = BarcodeFormat.QR_CODE, 
     Options = new QrCodeEncodingOptions 
     { 
      ErrorCorrection = ErrorCorrectionLevel.L, 
      CharacterSet = "ISO-8859-1" 
     } 
    }; 

    // Generate dummy binary data 
    var binaryData = new byte[256]; 
    for (var i = 0; i < binaryData.Length; i++) 
     binaryData[i] = (byte)i; 

    // Convert the dummy binary data to a string 
    var binaryDataAsChar = new char[binaryData.Length]; 
    for (var i = 0; i < binaryDataAsChar.Length; i++) 
     binaryDataAsChar[i] = (char)binaryData[i]; 
    var binaryDataAsString = new String(binaryDataAsChar); 

    // encode the string as QR code 
    var qrcode = writer.Write(binaryDataAsString); 

    // decode the QR code (full roundtrip test) 
    var reader = new BarcodeReader(); 
    var binaryDataAsStringFromQrCode = reader.Decode(qrcode); 
    var binaryDataAsStringFromQrCodeText = binaryDataAsStringFromQrCode.Text; 

    // a little hack, because the barcode reader converts the \n to \r\n 
    binaryDataAsStringFromQrCodeText = binaryDataAsStringFromQrCodeText.Remove(10, 1); 

    // convert the result string to the byte array 
    var binaryDataFromQrCode = new byte[256]; 
    for (var i = 0; i < binaryDataFromQrCode.Length; i++) 
     binaryDataFromQrCode[i] = (byte)binaryDataAsStringFromQrCodeText[i]; 

    // Assert, that the representation of the result string and the byte array is equal to the source 
    Assert.That(binaryDataAsString, Is.EqualTo(binaryDataAsStringFromQrCodeText)); 
    for (var i = 0; i < binaryData.Length; i++) 
     Assert.That(binaryDataFromQrCode[i], Is.EqualTo(binaryData[i]), "position " + i + " is wrong"); 
    }