原問題地址:http://www.zhihu.com/question/36989779
問題描述
下了個APP翘地,表面是個普通計算器,輸入特定數(shù)字后癌幕,會顯示自己保存的秘密圖片和文件衙耕。怎么盡量避免熊孩子使用這個計算器時剛按到這個數(shù)字或答案是這個數(shù)字?
注:小于15位勺远,且不得以0開頭的自然數(shù)橙喘。不含字母、符號胶逢、小數(shù)點厅瞎。
我的回答
根據(jù)題主的需求描述饰潜,這是一個口令的生成和管理問題。那么我們就需要遵循以下原則:
- Confidential 不能使用過于簡單容易被猜到的口令和簸,長度不能過短其中的數(shù)字重復(fù)不能太多彭雾,數(shù)字不能太有意義(比如直接用題主的生日,工號/學(xué)號锁保,甚至身份證號)薯酝,需要體現(xiàn)出一定的隨機性,否則容易被擁有良好的字典的攻擊者破解爽柒。應(yīng)對暴力破解吴菠,最有效的方法就是增加口令長度,所以這里取題主說的上限14位作為目標(biāo)口令的長度浩村。
- Accessible 必須能隨手找到工具容易生成做葵,而且根據(jù)confidential原則,生成以后也不能隨手用明文抄白紙上或者系統(tǒng)自帶的備忘錄上心墅,否則熊孩子分分鐘找的到然后就玩脫了酿矢,但是14位直接記住難度太高,所以我們可以考慮把口令加密以后進行記錄嗓化,自己記住加密算法和密鑰棠涮,或者反其道而行之,把某個或幾個能記住的object作為密鑰輸入刺覆,加密結(jié)果直接作為生成的口令严肪。
綜上所述,有一個可行的思路就是生成偽隨機數(shù)作為口令谦屑。
方案一
取一個能記住的字符串或者數(shù)字驳糯,用散列函數(shù)計算hash
值,取前14位作為輸出
比如這個就可以取60354186872526
再比如這個可以取32993841519355
覺得生成的數(shù)字太湊巧的話也可以換個熟悉的單詞短語再算一遍氢橙,直到生產(chǎn)滿意的為止酝枢。
方案二
找一張圖片,比如你喜歡的CP的同人圖悍手,用MD2
編碼生成數(shù)字指紋作為隨機種子帘睦,用這個種子生成一個14位的隨機數(shù)作為口令。
如果需要得到這個口令坦康,再用原來的圖像按這個流程走一遍就行竣付。
我們可以事先定義一個函數(shù):
ApplyForPassword[x_] := {
SeedRandom[Hash[Import[x], "MD2"]];
RandomInteger[{10^14, 10^15 - 1}]
}
這樣需要口令的時候調(diào)用ApplyForPassword["path"]
就可以得到這個14位偽隨機口令(其中path
為圖片路徑字符串)
方案三
隨機生成一個14位自然數(shù)作為密碼,使用隱寫術(shù)(Steganography)將密碼偽裝成看上去非常普通的圖片滞欠,需要再取用這個密碼的時候恢復(fù)其中的信息古胆。比如這里有個已經(jīng)完成的隱寫術(shù)代碼方案可以參考一下:
偽裝過程:
恢復(fù)過程:
這些關(guān)于隱寫術(shù)的操作也可以被封裝為兩個函數(shù)。
偽裝函數(shù)(第一個參數(shù)為載體圖片筛璧,第二個是密文):
StegCover[Carrier_Image, text_] :=
Block[{CarrierData, TruncatedCarrier, pixelChannels, SecretBits,
LifeLength, SecretData},
CarrierData = ImageData[Carrier, "Byte"];
TruncatedCarrier = BitAnd[CarrierData, 2^^11111110];
pixelChannels = Apply[Times, Dimensions[CarrierData]];
SecretBits =
Flatten[IntegerDigits[
ToCharacterCode[
ToString[text, InputForm, CharacterEncoding -> "ASCII"]], 2,
8]]; LifeLength = IntegerDigits[Length[SecretBits], 2, 48];
SecretData =
Fold[Partition,
PadRight[Join[LifeLength, SecretBits], pixelChannels],
Reverse@Rest[Dimensions[CarrierData]]];
Image[TruncatedCarrier + SecretData, "Byte"]]
恢復(fù)函數(shù)(參數(shù)為偽裝圖片):
StegUncover[CoverImage_Image] :=
Block[{SecretData, LifeLength, secretBytes},
SecretData = Flatten[BitAnd[ImageData[CoverImage, "Byte"], 1]];
LifeLength = FromDigits[Take[SecretData, 48], 2];
secretBytes = Partition[Take[Drop[SecretData, 48], LifeLength], 8];
ToExpression[
FromCharacterCode[FromDigits[#, 2] & /@ Take[secretBytes]]]
]
這樣需要使用的時候就可以直接調(diào)用StegCover
和StegUncover
了逸绎,就可以把任意文本(甚至其他形式的內(nèi)容)隱藏在任意圖片中了惹恃。
當(dāng)然這個方案也有很大缺陷,就是降低了資源的利用率棺牧。比如蘇教版語文第七冊一篇課文的彩色插圖巫糙,508*715
像素,有RGB三個色彩通道陨帆,以我們的方法完全可以存儲508*715*3/8=136207
個字符曲秉,而這里如果僅僅用來存儲14位密碼(+字符串終止標(biāo)識‘\0’
,一共15個char
空間的密文)是嚴(yán)重浪費的疲牵。中華人民共和國香港特別行政區(qū)基本法 (豆瓣)全書一共55983字承二,即時假設(shè)全部為2個char長度的中文字符(ASCII編碼
),那么也只需要111966個字符的空間纲爸,再用于存儲長度的6個字節(jié)亥鸠,還剩24235字節(jié)是空余的,我們的方案這時就顯得有些殺雞用宰牛刀了识啦。
那不妨偏個題负蚊,這樣有個好處就是這樣的方案可以隱藏非常大的信息量,一篇GettysburgAddress放進圖片里簡直毫無感覺颓哮。生成的偽裝圖片也可以通過存儲為png或其他無損格式的圖片在網(wǎng)絡(luò)或者別的平臺交換信息家妆。
彩蛋,猜猜這張圖里藏了什么冕茅?
(未完待續(xù))