2017-07-31 118 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"); 
    }