Some fun with one-time pad

Phil_K
7 min readOct 25, 2018

--

You have probably heard about one-time pad — the holy grail of encryption. In principle it offers an unbreakable encryption algorithm — each bit of the input is encrypted (using XOR) with a corresponding bit of a one-time random key, and the keys are never re-used again. There are two main reasons why this scheme is practically (and theoretically) impossible to break and why it is considered to be the ultimate in security:

  1. Since each bit is encrypted by another bit, there is no one-to-one correspondence between symbols. The first “a” could become “z”, the next one — “U”, the third one — “3”, and so on, without any pattern. This defeats any kind of statistical frequency analysis of letters or words.
  2. Since the keys are “one-time”, each message requires breaking of its corresponding key, unlike systems where the same key is re-used and breaking of one key leads to automatic unmasking of all messages encrypted with it.
  3. Since any message is of given length is equally likely (consequence of #1) one can never be fully assured that the message one gets when trying different keys is the right one. If you have a six-letter cyphertext “x2YzB_” it could be “cobras” or “stamps” — there is no way to know for sure.
Code breaking — a scene from ”The Beautiful Mind”.

The real problem with the one-time pad setup is how to distribute the one-time keys to the other party which is meant to see the output? It becomes even more brittle when multiple addressees are involved. It does not work at scale.

However, during the Cold War era this was actually used by spies who would secretly agree on how to derive one time keys before being sent out into the field. A key could be something very standard and public, like a set of poems by Edgar Allan Poe or the King James Bible (not really, but more on that in a minute).

Let’s see how we can play a bit of a spy game and build a minimal one-time pad in the browser with the web’s lingua franca — JavaScript.

First, we’ll need our encryption function that takes two parameters — plain text and key text — and produces encrypted text.

For the sake of simplicity let’s assume that those are of the same length (you can add your own validation or wrapping around as an exercise :-)).

var UTF_LIMIT = 65535;function oneTimePadEncrypt (plainText, keyText) {      

var encryptedText = "";
var i = 0;
var j = 0;

while (i < plainText.length)
{
var p_char = plainText.codePointAt (i++);
var e_char = keyText.codePointAt (j++);
encryptedText += String.fromCodePoint( p_char ^ e_char % UTF_LIMIT);
} return encryptedText;}

So, what is going on here? Basically we loop through every character of the text to be encrypted, grab the corresponding character of the key and XOR it. As a final touch we take a modulo of the result with the size of UTF-16 character set — namely 65,536.

OK, now we got our encryption function, how do we decrypt the message? Well, it turns out we get 2 for the price of 1 — we simply call the same function, the same key, the only change is the input — encrypted Text. That’s because XOR of anything twice give you back what you started with.

Let’s try it.

var encr = oneTimePadEncrypt("This is cool!" ,                 "OneTimeKeyThatYouWillNeverGuess");console.log(encr);>> ���'I��k��;�@  // \u001b\u0006\u000c'I\u0004\u0016k\u0006\u0016;\u0004@var decr = oneTimePadEncrypt(encr, "OneTimeKeyThatYouWillNeverGuess");console.log(decr);>> This is cool!

Notice something very important — even though 3rd and 6th characters are both “i” they encrypt to completely different characters — Unicode “\u000c” and “\u0004” respectively. Spaces also encrypt to different characters — “I” and “k”. However, one can notice some disturbing patterns which become visible if you output this to the console — spaces tend to code to characters, while letters end up being Unicode characters. This is not good, it allows one to do some basic frequency analysis and possibly guess words.

Why does this happen? Because there is not enough randomness in the key — it comes from a phrase and phrases follows patterns. What we need is a better random distribution in the key. Of course computers cannot produce true randomness, and JavaScript Math.random() is a notoriously bad example of this. Thankfully, some recent additions to JavaScript make the situation a bit better — with the use of the window.crypto package.

Let’s write some code!

function generateOneTimePad(len) {	
var randArray = window.crypto.getRandomValues(new Uint16Array(len));
var reducer = (accumulator, currentValue) =>
accumulator + String.fromCodePoint(currentValue);
return randArray.reduce(reducer, "");
}

So, as you can see it’s pretty straightforward — here we pass a length of the desired one-time pad (which should match the length of the message we are encrypting) — which in turn is used to allocated a 16-bit unsigned integer (each entry max value is 65,536 just like the UTF-16 char limit) array of the specified size. This array is passed as a parameter to the window.crypto.getRandomValues function which fills it with random values in the desired range. Finally we convert each numeric value to its code point equivalent in the Unicode world and concatenate. Voila!

var payload= "This is cool!";
var key = generateOneTimePad(payload.length);
console.log(key);
>> 춛꣜邼᧍ķ뒸裠ﲹ觜䐏 // \ue78b춛꣜\ue9bc邼᧍ķ뒸\uecbb裠ﲹ觜䐏var encr = oneTimePadEncrypt(payload, key);
console.log(encr);
>> 췳ꢵ邜ᦤń뒘袏ﳖ覰䐮 // \ue7df췳ꢵ\ue9cf邜ᦤń뒘\uecd8袏ﳖ覰䐮var decr = oneTimePadEncrypt(encr, key);
console.log(decr)
>> This is cool!

As you can see, it is no longer evident at all where the spaces are. (Some characters cannot be rendered so they are substituted with boxes like these — but they all have a different code point which is inscribed inside the box). When a longer text is encrypted this looks even more random:

Ὥ桫岹킊�ﮏﰷ탛ֳϭ掓쇑죊ᧅ鷿̽嶞鸝ᄅ庤�᱇㔲⡝癘ᘱㅠﮛ鍧괢픈캞隆↖蠨ꅑ將랹誱黔䲍墳笴榋艜鏰ﳯ䴫偃�奨셼₇纋哴䡪캻젇냟䣐씒ժ튱苅ậ暔覶麆簹䱌≞맣䨌죈姻觲ꔧ歽잪睚خ饣癓䴪爉녣룯䧱྽㑓쎫∳뉺噒짔噝鑋�䕦ꁩ쳗ﲮꤿķ᦯Ꮢ牧卑�ⷖ淽悾㠀顙�㡝⓬携Ű밑珨椃ᝋ᪔㌞隴櫄矇孃仑딡⬴�ꒂ䐏撇蕠⃦橄䟋䜿୦ﰃ她퍅�嚄♥࿚�騙趌䀎ᴄ럤橤杖樲滜㻼ᣳ뛆牟ያﱛ仴酣墚다㠄鋪蘖ᆸ玲◺叧궠磀栭桜ᾰ宮쀓�穮䯏릉퀱䝑榹戎巏탛暏敇齭䂳颭草叭蠙ㇺ矅欤។胉ᛪ㶰嬧�毶屭㖱䄖ꝣ㩘䪋翔拨㖊耺盓绰Əധ骼쪤⯎렢ጯ䩅娱㙁籠旅䋶Ȕ❗凎ꋣ᧨抏眢ꈐᖮ뺢ꉐ﹣蹉�嫤⎭횠ﲐ�秕媫凪❆찵⠋칂䴁䰭ᖥ⠝候 ヺ릎鑘軲숪遪鰢袅㘮ᰧ巊궋տﻹ᯽拡㫻痙।眧ঌ围뱤ꥼַ㽦똝䜸嫥泜켮�娾苵ᜨ饕ງ璕ō⢻ῇ顛㈣䯳迟�諀睟鳸萆ꝁ뿸冝韲艎썼ꦩ㸝�ᱧ白�鰤眈趇ਸ਼ꟿ㰞熯�⯾숈㓏꺻쬲彜월渀Ƃふ䷆聒騊䇒臍䊠柺樇퟿穅䗐↢랼ㄼ켣偃䰣�軹Ƚ荖㝣ຼ䎘፠Ⲏ셴ᖅ꾐쟪੪蜢꒙貭쨶뤗᥿߸㓄鐑⋍⣉〔팫�퉊᐀毪햖孚ጟ誳턶ᆌ숢놷粉᎞跸騷庍곞촉砭棇輂䚴ዋ듿騭꼑䴎㿊五ᒛ㫌䀜죦꺦ᘙ嗱鮪椏⵫ꢂ罹烿뤍鑱ᶕ꺮艴⽻饚醈붅쑠軭쉨翍棉샱饢蒉냤湋ꎝ윗㨾ᮉⵘ殉흡㡒ѱ”ᶫሃ봻꣨籾杠ꃺ즺쳷⾤⎺壉屉㸕뻬竼᧸앆ಈ鏿슑훓斥⫲䎪봋岬ƻ鋞鵁鑖찱仙셛፭⺟䦟ꄵ쵀ஓ█訧꺉冰͕㶑᳒㌼ꁋ版哫ꛃ軐㭓鍻甬瀕╝䃌ऱ钵視鼈缘抴勐ぱ�ꅜ瘠쯩峱ᗽ쯛㜋碁ῧ麫秫ᓙ✟⛴㣘꠱�獎쐦趕䲯ⴏ焕ᒎᡮ鎴﵊쪨췻睫㑼隼릈�뙻웲ፆ뺟�覿硰僔㢆蛹�鍺璎⃣ꅊฅ⸤፪蛽癒眦୩쮿鍓圲膕軾軺蟱诎驛짨�踃쾇ᘏ꩐﹪矊俛璵∛嚥혱檒皢壻猀巐�熃飮韇彀푮ᆙ᩶檛�峨䏦묎翢Ù磕欺᯹ꅩ갭쭏逕䈕辜䙠u潱롡蛄帵礲ꌰ�㭰�휯杫鋛閩麼筜銢雘댯�赟థ흮鳇굱恅泝鹅몆狧䜺봢綒⛅謘ꢲብᕦ킼㷄�蹂礟鳺ጱ⼋ץ�ꇋ긖顯趮쌌溨䠈샞䠫哿쭑冭绰丮麞䲽䘦藥粄ﷸș탵ـᐃ뎼돝褘亣諢ꂎ읗眓䵟撸说幸퍖痈킉绖♢距핖烚뜣烗ꃭ䟢햾혢ꔯ缽웲辞◀劣훎ພ艌㩕뱱华蹳纵佢鐥惪쁯劶뙽ẉ糪焴䮶�䤌失䏜槳皖㥠⛓輞Ƚ䅝瞦䛑ꁕ⋽㉞嘊婻莺�很乐嵏꙽哣�ᔍ䤼쾘ဒ�澓æ纁먭孟୙马䰎䝠슳돬민櫔摾Ƞ겢㈑眭쒩퇇飈⼃뀆Ṻ∔ᄱ㇜ᩱ윐뺁伇貺딑ꄝﱘ䖪鮏䳷숥绵翂쟕敉珞⁊䳣虮䁕鄆䱌ј�齭��關⌺ꁾ㰌提鴋郫冂㠬閴ꄂ〉ࣤ஛爁瓔㟨钟篗롑뭒袢೬똝ꎩラݕ휙᪂⓲ڸꥭ搱�࢓ᙏ㿽춫◛덋넬쮀抒탼컝䓟ᥕ띵횵押꺫랦䗤∷R퍶룻䶊춪뢛㳭嵓⹬쁋㉿�ᠽ牯㔅먵�쇊咑ኑ⺒龊죤懤ꁠ옯혟卼硏嵲䞐籜钀ⓍᎰ뗳钻䛑ⲇ蟳셵쁂긠䌿售㫾࿋삝糣揥ℵ楑闦蒎꣟麈䙴�㾆穀贅썄눅䌊ے뿪ꃳ誇뭰찱ࢺ佌障묳ᾗ郊બ픷䓀ᒚꖓ锧弜硥찿嚀飂뱭ᩈ㹔⸛爹鿍焗௄灩趬왣皊⊮蕆Ώ٘⫝̸㡉넝ﭫࢪꘉ罢痀톺䪤蹒䰜む腭꧘륛麰蓑⦨餥刱醲﫼Ⴗ㟟⿀헞✑찀ᣄ䉣졢每붺픳ꇶ䌰윻㜅讘헁㎥�䷩㨆쩁楱쾒඾ኒ鴲勂ꓴ筎敛约⃺ힽ⵴䨻Ύ㋙ꎠ뤬댐缠Ꞿƙ೗븵㎇轛먹꿭纺ꩼ䕊ᥫ很訚䦚珧홚獪漣膨ꀻ㋯맭藖戁虔἖笞硎췡뺄讽슗៎ꬮ䮕闫_᝱汆梪堑ᄬ㡶팪�邇ꤩ䢇䂅讍绕✟총ሦ뻪聬ฟꌗ뛹흻✜〒⹅鏹녇ユ圉翓∋锢諭邽삉葤ﴭ︁⢌ꉏꆻ쒄괩崴螞䞆鮯ङ냺�쳩얫뭽⪙髅ꂥ둯ក�᳡เ뗷◢蝘⸃鉧⣰겓䄬啿�缥鋈﷎赐헜ⲏ阐惼⦅桞ᑊꚻꅫ廆街숥崅區肤㿆꼪녲俘ફ鋀ྙ닅�캗ꊢ⌯炈鿉鿚怢拂޴詺�쯫꒦䡍ꚪ殓ᖟ숹�嚨㋽θᠡ蚽宆ὼ뢈⯥ᝥ詺ᕻ樌ퟁ�䫿ࡡ澺鿱갳햱鰣ᨧꃚ声ᮝ㵕譬쫄⊢୶뚲쵰塻彐ꐚ뽉ᆅ㥵똴猨ᨷ㼝⤇␷☋嚬愔ᚴ恬�띱⧧횙ㄦ릹䐚曤ﲄ洀꧀푰발鍢䶓ﳧᖖ올근聐哗婋돽㋪먑쑎ř᩸ᾗ堋ഛꕑ⌶嬾쾺졡Ɛ슰诇ꡌ惭棇麅ࢨ긴pꋀ言�ꦦ鰸惵㤈襶豔魵␹붚贬䛐䝂㬓층�῱錇璩㢔�ᣓ㧮뇢NJ팚蠣窙DZ鰯磀䭝깪냱분䵐䷬봮�ꃘ冻ٺ㾆쥉㠟김젖冓䰊俩ᪧ∛砻鶆闘㏿臯㕳隞翕�诠ꠄኔﵜ怵ࢰ⽡鰜蠲ᅱ�፱ˈ憯憓☇嬏ᇘ淝ꔅ䕺㣟蒤綈ᡆ欷৒쿕఍꿸䥻⪨ꆕ徣૶댒ྞ㼐䰲﷨怂麛ཅ콢꽇ى蓤疮�骜쟮シ猻�腻�壱⻛鍏⺵췧퓝ヌ겚끭ꓨﱈ栬瞪衣魐ᦋ撳麳દ鎟胋䒠뉩弟꩜䲮롮ꥄ髷⽽ि蔌哧鷸̷뭞ꬁ琨얂ׯŦ鉅鎿⻣ᮘ昱绑礱䭩䑛恎ᮇ秐홍쩶訣㦅袀뇤唁圉ǻ࡙룸覹寚၆隘埂鄙嚎ύᦰ湛藝άηꘛ寗䪏勦ဏꁒ辿鰢錭탵楶뛉꼵狞즕⁤埴纓饊໲떰㒽ꪥ樈ᚘ⃂뫁禹蓓眧�㺪䭬쯪ƴⳋ뙑擟髆㠍׸㰄硅恐ㅯ⿕죍㳔뗕홈숨୤삢㢘繯䅊䐣啡轓껼࣒졒︝昀鰆르릮ᬲ翱퀠畐箏烁⧴탣௻忓嬣䴻蛋塙螩䑛푢렐䙃辮셅梗▻挥鲁杞忔戫ꎢ�᎐롅Ⳉ㒩꽦媠他䜟㓴ﲬ⥆㽹◳꿭⪱ꅲ톬岿밳간ᔌ㲧糾郠蜿鮺ᘑ舰�漢劤常놩꒽牗滝夕᠇䖂傰驌䕯喍깊폠韆軏ᔖ욝輓듹臫⺄∙瓦�䢉엯渍뱗슻尰糦ꑲ蠕鄑�ᔐ�ퟺ㯬ꟕڼ息孇䉓゜ᗋ䶆ꞃ을唟㶶錏툞䊱䳹쇺惌ﺴㆶ◓裡쬊ꕛ譿斻휧ꢻ⩫罊쏅¦ﳪค褛཭巑ꕉ䲰槥⇯ㆿ㓂샟궉袗ℵ쵅΍笐瀼቎뒤ⶩ蛒渣欤싣䳱멂萩矙鞬⵰❲퍂ꡱ꜁䤟鲥͜떆棪赛连垼珹⹤辸諒睊櫌૓杆嫠➽㝦㿾橄�警姫谒Ƨㆥᆀᆄ享榣⫡و苲䏐製땚식糃ↈ蚯昍㣇ﰫჩΙ暘ᪧ蟕쁊ꌩ浘鱇䨭硍墴句⭝鉟懶୓勂圢ो绌狠聰�薻⅓饽齚断ࣶ姖啒碟᧟쏰㯩㡕࢒壖庯㨂ꪢ燅⍜驆嵌漛뮬ꀦ瞥劜ꋮ㼤닲뙺氷䷍骿쾁㍐矀ꧪ뱢感葳틪꘱䆂�눎趯託ૂ架৮㚗졫둢㊢䓺곔ꖋ嗻⏔ᘒෘ춮搴⃣伸ឡ藬勮쿍걨雉仦謜邊녺�挒೹섙胔꤮�떭힒탳饜ꋉ樶气㮗Ȕᢤ뮓Ḫᢐ跮峂蠶耨ꡜ䨘䂫蚛㄃跭⅖仇뻎��㚑쌷Ẇ�䬚Ô㏸康혰灰줹츢砶뙓⌿䨟䔳㽘㈄諤ď鬤己䡈븶�퓢ធᤩ␀뎲ᔡ谘¡᷀⹑⹪殕辏紂炫鰦Ƶ錑稹毊䈎౐⨉¹籣땬⬴ᖅᆓℲ鴧︇趸ᄂ�켯㸦﬜�쭌軉鐲侂ﻝﳫぶ�ꀎ빤㫞졷줙迍茐ᒌ틿缔溦싐镒면곆ꅋ똧쟓끣憐슶쮧⇿뀱渉ꂴô戒甙附ꍗ餜㽚甔�ၔ뻸蚔縛섥ꃤ贀霹㣘滩隴碧팝⒗ჾ⚥Ʋ䡚郀쨴㼭搘踤첈⃭�뗤�௟윷䫶䄦鼑�뉷ཚ備섄큁╜ㆨ寊�㯄녃裘ꗀ쭹ꯋ柫羴忰觇Ხਓ蜘揺豍뉃ዝ뚢�圇麭ᵠ⺿竧�䵙ㄸ䓐⸒孠ᴁ틁࠙ꧼ✰캍ⶀⶡഥⴙ箾峉빹盶쏨핗ݤ爍令ȴ櫠鯨䮹ⓞ乗欌๛繮䅿ꈇኚ螽茅녂읣ᦫ�秉ʿ࿰靰뛜揲鑇ႆ敬彩뉦䫢ﲠ齢䙋؝縫鱙갦単폚鞦䴔⥢閹ᙄ閗쟵ʼn暤瓁㬝箼尕瘆푪ᴎ筛镢꭯켞Ს㿺碮禠鴣㰽菭␰郥呡慙義墐⠿쪮麧�钊쎎䫢䀀ꂅ爔횬坢嵌智퇜䔲곆煛뙍앜⪡Ꮶ钗ᙲꤽ⦀服Yꥅ谂洿꾒�㣊ؽꀰ鑜궷봄ꡖ秵≉띘䬾如娼纝쫖鈆镂찑䜢긴�忩嚀萜麤ّ殈ᦳ媝톜熀氓•ꛗ�쌃룞⿊蹿氇륻婭专ㅂ⧠뺙揈偲똽⁇늣侮὜售菒혵㝩ꕴ戳ಿ�鍧㧏梽쀔禒蕱訴末⥩ꡮ戇䗕闙≸绰㡬瓖ꏮꠢ巇雸흓뒧ᢹ稡醨缝䯱ﴧ똢綢쓂凡緽繁뒓蜵ᵷ垌菽睧戎ℂ㊍湻붆함ᖒ캪傫᫗⫞蹲흕�豲ׇ咮홚࣑硒㘗ﶒἒᯁ鰯你糟ﴷ꫼鈽筼뎔딲⚲䜍颓ז㭴궒ⴚ⨓됈囲竭켪扌魡ࡢ喑袖桤폍묓ꨨ譭絖厑苩ⲕ슞ﰭ鰖腞湣ᐗ⟲횒䖘⫻デ␺㱯往䁯셪区䘕�હ鏡跠Ტꂘ�⭭繖︌鱈춀믧翧ꤥ⭥⦇ҫ憐ฯ靬鰌瀔혡䅟⿧䡇遽䊪垦ꏐḣ뒑㹮瀞銊뷖⬑ᅶ⡮䱞檓⿈쵂절吇䄄‱ꄅਠ夘ထ忀흛識鋕㺖廅琦ᚠ䄯笤丁삀ꯣ⊷☪㖙ꙴᬺ誇㬟阹裵⬢䡿족㍑鮌঱�쭦赑鏮윞䇜㋴䩵薫䩳ℕㄗ⧲찌婚芀㧩隿櫤钇ꨄ挶᧰댬捳疚驖ꓼ닷齼磒�픖ꮎ鸬彠䖝ꪴꇡ䏟郶恬⸅㞏懍鼠卾㶵쎧됛띴ݍ珎肀ᡟ饈剽똈撋㑄㼕瘚폪淯떁괓㤡촲涋ᛡະժ㸳ᒿ颪䦔馃欻ᕘ㓪ᣬ铘࠙푼٨砼潋㔛乓夿ퟔ켉겭卯⍏ᑨᝂ猐�鵖ᮚꋀ젿猡㐷灣굉潎젢㉈꤀Ꭹ힅�製嬉㓐⧱ᆼ䵗䒱끮㗼粋哂⥈⫾庛᩹Щ쉑꘨潞૙价⚃閿㞊䪠뒄﯊뫾瓔팀헲덢nࣆ溾妊땐�劸ဦ赅֓毭଎牍帹ﶟﹺஜ怸�繜ꅸ뙶⍗퀵鈓柅ᇚ욱⚻�돗瀊甙兡껑霷黇겠�ꢴ�ꩵ꣋ዛ行䠰쵥ଉ氿�蛯ॹ�ꭣ祭⿓廷톊蹄줐ۓ撌쩗誄炔囷ᅁꋛᣴ⦓Ỽ픵썈Ⳬ햀윷뺦볋軯棼鉠⦲↺㴵੆迯얷ꖂ妡太鮥䲯Ϗ孯⴬伅㯕騢ᥬ⾂핣ᦉ⺁퇋๠䳡鞴ꢷ줿ꠑ泮⎱끷띦힝랴쑣궙녦⇑챋뢔腸빕鐫ꔌ塔�꧹䒸䮂迂ᒆ겥䛺஋퍗饫న浳蓮■ൈ匷㛣輸若糧ルぜ꾤ꋠꂴ呈纣ᶺ繁袁弮칮ꖤ픰奔鎞ﭥ컱峥թ᏶�䛤ﳴᰑ黒ꀞ釷㔨К쪞쟡뤠�嘫쾗坰ধ뉻㾄聶㞙爀㖧얆㚞撋풦䠳㶃芪揗눂ݗ频䍺ᬡ沤瞋뢳띗⭾�Უ䢇ᖄ䫖큙쩑憏Ꮼ摋�ᵈ䩱왎ퟡゼ씲ॱ✋੕䦌ᅵ跼橽裷⥻僦툢ꄸᚷ꺳艫覻ꋨ撕桱᰺ퟩ㏜籼猳稱ಾ轾휷暔〢Ὑ灣뚬덝䤿獹詸痞缲파箈顊ܸ꫃⋯沊ჰ媖݈῞墳젏ﳷ傘킳锭耷ﰘ줭䦟ᮥḂ⒑뾏ᘴ늖칮᭙菣곢ϝ쟨蜅⽫䒏볩汾攅둵Ꮮび䯷遰⼁篁摀䗖⏙単‹ᱶ셅컰ᔺ䰧褦䇣⃘ꌰ꒤䞊ஐ⏮髶쏵緾锆엚懵ἢ둮❊Ҿ鵷졸臑鹎嫹읹ꃍ鞒ጋ꧱ᥒ᳎쒦Q䴩䐟䷚㥤傭귪鄍巹䋧蟟珽�ନ犿祒쓨㷳㵃჊놆뤕쓫씄橌ڨݦ폍�쭿�Ꮭ篜㻮罁裝ඥ죑뿧抦퐛꥓齃᪼鎳硦᷵刮<醑程嫣�洅偌ࢪㅠ麹㓺怗化珛ꃋ䯾濄쁓鞂�䡻榅⋖뒑헏㍖㍐뢄ﴔꈼ譎筋擱స洶鯦▖댲ꀌ╂篪릆䥪⾇᝼㳌韗㡸ᨇ絀ᄐ⯜Ā薞믥愺�㕎剧妼豹Ⰰ牻귐ᴐ暗焁㢸됺ܧ鵼赩갎ু枧䰴퍛䁗介݂�ﷰ᳤톴�᫑举ᭆ查䘠鿝尫旴뜔⋡ࢌ㧙䋤헊屼䦌랸⃲娶舶ਇ�둤䖋銨⇈鱀屸칏荎䫀⃚蓻꟎虜덅뜅帬═ꛪ㉘㶏莦跡쁵ḡ쐲鵑㗺鏤弹1ࡃ㪼_呄쪋멏�찺銲↓坙㺁톄抛⑸ṋ镶헮鐾쇆苏䪙臈愆᫔詣ᨌ㽽췫須䋺쒍ẝ㞼즚␍詐浡讯豃轉햐؉绀䭢加拲ꪼ␥䏀�調�⢈⫑튏ဦ鐏營�쀉댲邆苭ҡස猧䏬葞뚣鳸�睊艗ͅ─⡀౐᝟≱附湁ŧ⑱婹莺鈎敐懥唹녔窢牜㶊驳켬岊迨㎶푸Ↄḣ蠌샀옣戊뺶か몒酯톯嗽렦┾萒喅㙻໾쌪渝䶺ꍩ툭흝ﷸ顎ⅷ믙믗꺎渶洖皇쇺钺᷀摱꓌厮叽蘕✩곙뙛꽫ﮭ⑜⣃諒던䛈硣쾕촒槠흼௚ӈ㕣轏菍楞惥ﳦ冥㬖棑ꣻ碠阴쟆䐁ꚸ䪷啯帖碮穦阆ᗖ失纇ઑ䮫�㼅솬⒁崦⻖Ǫ돯ꕱ驆壴⁇㠆ꠗࣟ艳뎹唱窤虥�ჿ㭊䆨脹갺׀ꤶ쁶⪧닁줉嬥蚥ꉎ短瞧�ﮥ榯ϡힴ䐌殹珋횷ꓺ梲貃鸤ﱜ㐯鍗擄﵂役魐輄索㔳씰潹捭➦઄ۄ᰹쯭໒楷그膇隳䶠菋�紫ᑡꞁ賝炠Ɔ㤘쀆넴䝝뛈뵶錒䐽ꖩၶ떓ಒሟ黴ꨇ捶꓊䃼椲쐹麸⢭炻ᚔ點藱佁뙓鬢릅暴콜沃葤䀁슠䟮릔ꪗ餠岁㊼⤖ꡢ欓璡쓝‟òﶌ衜࿟߫龨蛒夯㎼橡⢯끠骳猛䏚퇝굼�Ꙁ怑履ᗇ鞎ᕺ孄ࢿꁩ뻋쯗菇쬝믹誄硤䭢訩�ᆌ襹ꀴ쇨궀￵滇륯旆⤇ꃚꈏ㪞䜲ﰞ�㸓蕞틢￞☠巈ⱴ掲威⌼悸⪴哀햰䗎煆ၵ柏卜囗䑋羑尌궗࿰㞀ც眶ⅈà蟾睐땨퉘奔养袽⫥씜�̸즙㮜ﺬ⧞忯�뤎鋁逩ࡅ륚⹋촓씍逭⅝꺌祿댵栗⽨틒อ憭㘕쳝䩻�にࠆ泾Šꡧ鑿븑캁㖕�⫯x袢镽ꍙ鍦谧䋤簂棤㷅᥈ܘ뷤曋轨ڑ똉ꖑ룏䕜鲲ﰑ뾱궊㸮폥ꡱ廮✺Ⱪ㬴口鄾哹㎤鮗罼ৰ饝뽳⟣潺ᛥ唻⫃満�얄흳碗糘솜࡯찺再뾻�溨鶎ꈀ⤒⤯䈶鈷炁읈╠蒶䇋壘㯛쇽脬㞐ꆝ푆鯵鷄愩웸꧛뱧梫㑟尬惽끰羰ꅀס叮농ꙝ뻒湃꺫정孵筂拱뷭僱櫶䄓珊둥姲艬侃♥䓜옴䭅䍭墺鑊᎞㚼솮岐氓迧︴ꅯ㍎뤳ﲚ믇敜�饌궒ˍߧ蓮괷퐧㼘ᳯ䝌㿑䝒㰳㖌䈝௟ⷤⵑ밍흫↫⹒筗❘᯴ᩅ䏔䈵䲵ܦ轪빿ᤘ�쫛戓퀓�ⷸ슛ỻ饷꯸㛆栲⁀ၕ싷᷁윰맑諑萕᫹赡쑐绯ᫀ逳ꨬW퇏谐琠歚혒c끲㓲ᙛ╷唍븹믮�ꀳↄ冟ᗾ姾睨♠ᰊ⏟랰沺饕완⻭㈍솭叓覠脪ⴍꃈ᠍崓ῢ諫蛸瞨쉱㓛غ♾誆㔈䲢璺ꊴ湪✪ﷄ陰荇ٖ芰걵؁옚ݩୂ켥ꪉ㦑䳷Ḥ짳蜹魣ꮜꟍ✪˒釁柨䵧쩗鸾鰾뉶뼲倈氏爗ᅏⲖ亪풪楒�㋼臊樰䡹盜餼໿ﱣ皻沀⤟캇꟨ꎆ墥彷꒬뷵શ1峧窝ꉞ姳탼瞃줕燤ꇝҔ볜㡡厢춃죉ᴥ붡桧봟㒶䞨!⪎깼茁둔阔떻拊衙㠈媈ྸࡉ૦蚯ꐹ៖딚꡵㦟佸ᱤ떇뭂濸⊚�쇴㰙늼毩㝛腄捻暜琴പ絟皱흿䈰됈鯼똈�愋❯홇⎬㘦倵䗡괐邱㜌揰䏖쪋Ⱒ턝�拆븐办铠⃺䑟ᛏ䏍䯸✐ᷴ煃陖濣夥踑▅ꁿ敺��Ϭᆎ㤋୕굞缇䴴筌ﵝ熏隊�樜豐␊�딮ꕆ뻋ᕬᨣ䏫꼼␷룢�ᓼŵ㗵Ҵ탵纟㨭繣驌䉺缄ﯧ縸䮇臵涰갇앴ᠦﺙఛ葘⭛漜⛪̡ꋁ఼鯔늂얩ꇐଁ륄鿮ǘ弝兊쓯�ᭉ朂傖襗决�⚳⎐辚暹䫆췻鍹剈ꛭ쵕轳﷤⍤⹜皁륰癊걑꫐㹿㟐潥ዒ𥉉仄䯲勈讽鴀㆕ሁ칻ꌪ璖挀求䵋ᱸ⳱䤤╫㰱ꮱᇵ扄闏᎝떄➄体ﴜ宬⃀浹쨾⼉雦Э홉ꎘ煖愺췻䕞℡䙖*ⳬ᎖蓍ᔙ쬞䊄ꔒ໧橺ࢿ䷞챻愢햡堧註彄瀖绎덽ᅳ�膙ꖶ⾉ᚙᨶ﷓迣�Ỏ宸⳹�葸詬ɒ혍㾱㉵倧醄לּ㤛豟ㄝ紤躯⠣瓼鞪蛤᫳෎᧒�皌넩湏↷䆻樃⎿蟌흇⓵爪섫儠㘋ྦፓ螃虠딿뮏놼뱹ﲻ깨젌锵蝎꫁喼퐪盫䡏뽣�ᄿⱆ푪俬쾵耫凢੏踏櫶펝㑨흟犡䪊憴ꚯ䲂≇됯ࠚ༚룱㵥쎧褎錶屺帗砄ꌐ츧俼㴂笠㠝⺷䠉걻沏䧝鯤鬙哃탒̰䪐愿蠦鈦縯䩫晙㳧�▞釀㢓詺骍됗쪫豈炖Ⰸ締壤뤡ૹ꿸쬂蹦堢沿쇬䟟㼫喎∈�肁숙С놈✎ᙺᏇ녢뢆伫瑴醟墳뿠坹괝૊蜌�놓ᝤ哜쯓 싋닃孝抻᰹耪餾邏儨곘ࢬ⹹Է锎焝ῤ㯸♈薧诟Ꞑ沊讫돜镔䣜앮脅쇕戛鞻媇홨靻嬚ᐂၠ੝숈嶭奆㛤틤睊陪࡫㍁牬亼腅ꐭ띶ﱺ�ꉰ��䣙脳ғ㍇ﻈ⿂硔떨鳒㫤똤ểꀸ丈ꠉ䲯솅凨໬컩씶㯪埿똘쵈⡄⠢恹튈�멎裲忴䐸Ḯ�齟蟃騛�좢厹끷㧁릶䗅뾂ꗙ䋉퉕뽑倹᳕妪蓋붓榺䓻ⷂ鉛ꨎ౰ည썶ⷦ蛕ꦵ줭᜺⛚뗾쨘엿ퟜ깂ꞇ�﬏鑯塼꼆뗢挙ྊ뉰䘦Ä꘢ûۯ畃♒숱黷柒칮袓渼ॖ挨琖懈镧瀴㕄蜫訨옃欓ㄒ齦ᗼ肏롐婒큱霧�㵁爡纻憤蓊ꤴ횉ྖ䓇恣끛꺢㤲࣮榫㺧ﰞ㰘鰯墳鎙䭾峗⢨㘴矄ԓ↓蛨ஸ᭧栶ꚤ�ㅍꕒ쑡괃벱荩䲉킸ꔴ坟ǍT䛁쵇⨕躉Ⅿ쿉脐఻ﵫ竄⯁柕듒唏ꊚ㌛ڛ轷꫐⻨⋐鳾粦꼒輖�롊㳇摹〸ߓ멾꽐뺜唠䰣졹邍㲡鋕李䛯⭑裚혟옹ᗡ雄㫙婞෱싢옢⫋錥碪⬕ﰜ䗇礣府ዥ薁铏쐜榜놄轜籲뚃旅關䃃悮�毺뛁䍜ꗌ棬ꊄ翏烸搜돘⫽촫⶚꾶嘔桾죷㝡�᳅悰湷筞ᑯ塊�땓딌忌즲砭׹쫊⹐䁑曆븱ᾄ뮊앾耷읜璾榴➈혋䝦នܳ䷱ࡾዎ梤㈹푏챺硚ꂭ쥴⫁᧥䰵狧㑬ﳀ떛ᙑ㫮鏇ంዩᐣ㺐䀘ṹ瞑嚠柎䮐䵉ﳖ䰧୴鏀�쿧☞ധꏷӈꜬ෹⑑줻뱦騵ꗛꝃ艾齝逹㹾교ﻖ건宇홞◖독ꃁ⤽髁砃玞뵫䣦鶯풕⸊桮ꖣ煶꘷⢂գ◉ﳮ徤๣喃교젆㴱驐闫频꫞鱜ؙ瑆⮘嶹涖ᦁ꣥ᨠ諷�攙귳귪癮愼ꢪআ扛콉沊짟䁦೭ၜ즱⨍꤮ⴔ饬꺔뙒逰ᡨ옸�縅錯㶎퉊�琀噕枝붚ဘ㿩ㄖ徍ଝ�骝〚숖垢ᣠ�᰹씘ዥ㽙┛꾬㖭ꍬ诉酩攎伸脝먘⨀娙ⴥ仒∌啉귧⽼뗚矼⛤㻸麿ᵈˠ싋帮暚㪸쭀᭗Ǽ䦮橸뀅⩇蕒梄먜꒯벐⳥⓯黨�㧼ڟ쾁瀆懝镶젳�꩗폡呴꫇䰨ꔹ䂮觮뽯ธ亰帡䇡אּ踼ꅁ♨疰솕䑉坧䡗䒂ꕱꎠ⦡摾螛멬끱뾼⸟ 傻o噊輹咔晹跆츪룬箷糌쭍ᅰ彨ᅬ☙쵢䢁ꍢ쾦럥䷮ᖀ⧧稞䶊뫵삡弓ᅧ拕䦼Ɦ끟峝츃䣓ᆭ淽⬊柸Ꮥ쌨廆慠㥴輅겞ꭟ㥎⇮൩玧㫂噂郦͒槟멡囼蛈ㅀታ屿硼㍾៴⯼㵲ڈ岚�Ɱ缺靹白혎뷟梖ꡣ뗄﬊䥙⹅ㇰ쪪熤硤⦻퍱藵꓂封㡭㼯뱭雕伊ꃍ⠫☲鳝ꕶ⊿ⵠ뵝癶⛩롑螮ᤝ竷瑀꬗댹믷㷘홒㐇Ŝꏘ涌ↂ஠浶꒺㔒㔊⣰䶉屮짊曾霫鯺㒕褼蝱䶼駲縑퉈鉤亴锵뷜ᷢ鶝뒟賽螁ᨔ毸�̖泄蔲�륁ܵ吟ԏ긫惨쿉듹҉韛׆飜軋曆㌪漴⡚⡘岊Ꞻ沴蘥鎎퍻㎟ꝼﲥ斱ꄎ፱뇥㵛쟐띘욾跧䥢ⶢッ鴥骺͎ᑺ辑끚鞺�鰗丨㰬ኜ阳�鶐큝䣄ꮘ칵鿩敉ffဍ龔˒쾉ڀ謏︛㊈ʭ跿瓗ࡸ◤ꟶ⫵ᝉ᭯跎엠慗乮怋냡鮓ࠌ癷囊꣋ㆂ깨⻄쀉爦꺔关ﴛ�戄ꠦ웬㞚獏ᬅ骻䈋羳넥㍞㧻䯆⾈縟ᬌ㷶哇Ǻ͕ꚯ멗䋠蚁衛綟췂٫κ앩銱蘵咽惨媾캃ဂ툷욭䢮�瀮睅쵕蟝墿ೡ뗗缐෽昚ו杭ᠡ鉒䙬ꎳ魊鋒䟳�팸ⶇ庵뷸훧뺅ᡁਖ਼殙涐�Ⲟ䋗㜷皈䪀姎�॒㻱ⶮ픭⩴ḍ鷀깦句렐襪푋䥨⮈僕쏥�箅쫖ﭩ饽땆桝挡ꖍ쟉톆�꘱Ṹ䚤⻛ꚡ潂㳢铛ᵦ瑽킁̇�䳹㛼ࣸ�ᩁ驎ꜭ⍗똜�춃쐛㢏Ṿ膱染畋༫㠘᷑♜ԓ鸙ᰪࡓ讧骩赼⑔庡崽绎칔ﱞ䮉䍂溫者䩠襻깚춽齑林䒫மꜞ总摊佡⛨锊䨝咉惜黲狋턹쫔鶶嬢쭩๽蕟㑕꿧戮箥쀺ၖ뢕ﴼ㏤ꀚଡ븣援狀㜸齕㦙㾟뢾넜홺騧ⱆ學ᥲ뱠Ɥ⑔৳혶ꘐ閶㾗䂱␤ㇿ궀魖㘪⇲ᯌ徼棑嫀໺퍁Ƥ㭒ꯎ�숧廪옚뱒ꉁ盥隨멀溜杌搩다틇椨ꨁ외范ᡊ殘ꡥ扳욶�ൎ䋨辈쫇㌕캉ﴄⰣ䌑਌兄긄뫴ཧ鏃⑃禍픟쬞⠛番棉㈹ᰫ幊ⷬ耡⾚됴�㌧ꪳ窄ﻶ㡪ۜ㵵惷䭘饱퍿Q쮏쏜穏ῆףּ쑦퇢겣哅荨봃ḛ鐍컁럹懕폫咻뫥鑹䙁䗟≌䧢벾琗ᆀྊ둕䣎瀋㫏逡銵�₅藸㻤ອ淚뚻ʤ悥孀ᅰం勒碳ᵍ圠䨨布�龓潞帩똥ሇ�տメ⼽䌇텊ꬂ왗맣ࣨ짻몧聠Ü娆㽌踾壕빣ꄖ஝಴頵㌄፣늓穱჉ꑀ厃ኤ鴣緔எၮ拲쏽﯃ᕫᩍႎ䊻鸂᱉ꄮଡᲳ齣퉤髝⽍눑狮봪㽏剟뉧塶掺魁꪿뺦ʝ�᮳ၷ良ᕋ↙䱑㹤됊�﫴Ӊ틢䑠忬餦畱蝳累嬕鶢쨢℄숆봩ﻊ꿒ਖ਼呅´�貫尵톪鎨釹㕩꯱닱ㄵ緽ヿ砥Ⓖꉟ鏲�㐟鄱﫫厃嗪㓁벋성Ꭴ頳품䴴腚⼨彊큹윓쫑뱈ਗ਼ᗟ�褥羣ʧPᒫꂴ斪寁ῼ閭匹ଇ걡앩ퟓ舘第矤鲡鑔괢⇦蝓쾉皶脳馹뱊됒ϟ좶ヶꎚ戬葙軈ᾝ➮㒡䮯鋖旦醁竬鋐鵴蓔ﮃꮲ姱괄䒙ᇚ틥韯捹꤀�孄퉼﹡諄瑇畜됲᚛껄ꎋ룑�ы薙Ằ矌풏ﯼ쎐�ᖰ圏T╈╱਴芊߶痲生餭ꦯ￈ꎞ倜뻌彼숗沵퍛ῇ閜䄟䝴炆ꎢꔫ鮊硘ᶿ亘触䳹य़ᚮ폘艵秋᜚襁奺輣卡W㓭쥥ꕢ檮彾籛癒ڥ姼㷕͖奐敊㙍✑뒌啅痈斒閞菞坐慝걔ଅ랾飶蚜┱项⤉ᵥ桄ᦘᑠ蒛랿퇩䪵⛬銖뭀闵쑚ꨛ똉땮鞻⃇謺➎촥⛹콈잙稵ᡞ砫㤿믻䙕䡪攅힉⿈ॅ쨺Ꜳ㙜徬ꈛ鬜춊攁ƿ㴏�햕�祁�螽薪锐뜪宸嫗揇枌偡�⯒퐬軗湚仹ﴸ譐巋嚀ᾈ拽着̩�倍䍈䝍犟㇉嬕᝟莺꩓Ⰵ�嫮跣糑㾬ྑ嚜䬰셃燷鄘錄瘷ꦄⳠ閧㸥땪䆵皏휬頯믋ଆ簭舺땨뻮ꐫԖ놹̂ၷ櫛〠ꥩ㲐獯癔に裞輭�妅᠀鉝靽἞╗Ç㼆睾滳빇듽ꃶဋ틑ઢﮀ꠸ዷ꧃鎬괳ꟼ戮徦㸈䌡잳휠혐쳅翂궥볢埒徝鎏莦�嗻匉䛿䣄�渶殓溉녀ᩘர첾�觕晍츒௴䑋ẛ좰⬖旀톴᩵曨溛�뎳휹㋱糳셨䆚歗螠縪볟㠞猳ꗬ�チ嫵汥劖鼴�遆剃a虄䄼뜓蓐⹊⺝闠屽⤦稷籄笮쵦䫚퐨⠲괐홆愍먢큒鷽溹靛ଅ䣉鎲뮱Ș�꿓롨䑉䗋樉侍�䑒嚇ࢅ丷捜��ሇ�킕푴ʨ樍ꐻ龹餼勉䢜⛔웲걐겆灠厐㝙귱뻣丄年窨⠎鬜᫁䅉ﳹᨨⅬ駊鏨䲷ﲦ宥墦谭Ⳝ쉊먣풤觛⣑ɾಌ὿䪢ሶ⯏擯ꬾ酉㙸윻ﳣ矜뮠㠓킯絅炯丼힑䷀쐬㴐꡻㫭ᷯ겢䑃뽹᫥燎鉀ヘ価탻䭢ꕌ້๫忼ㅞ穎웎惜㹬囼溢윞瘶ƍ䲳᷊龙뼊敫칍圤祉慸摂≺쥗ꇯ롂烣㛂藨�◌ᬝ䌒�卐ꚿ㍃ṉ쵥轰꠿晼檟骵蘪鑧䒶᜝簕蒯䚲㋐႙꺸戄﷑顡ꃏꀢ손㖔卑箍怚낪﴿灜䔌덪죕純䘟娥䩢﵂䈝�㔹凐໭￘昫깲ꁑ갍왫駋⡘ﱹ䉤礪螝娉냰흷扷☛싥扗ῃ䋨궔ꨱᄑ柳䵡ᩃ嘱䀜彙췌汥콾묚ེ눢닖↧ᵢ笈填Ꝍम関黷䕟桉Ęᓟ븗蚮졮㤘도㱶숌遤굫୸ꖭ㴇뛵费戤㌀ꌉ袾㱤봁ઉ全ເன㦆ⱘ刘䔿樎ᗿ䷭䀽ꁱᕞ⺉轔숿璠«玑㘌৤袸ಹמּ鼕෼鲌輪K㭈匎ᒡ☽歋臃툨ᴪ뽹�ᄋ除郫ὴ᩟㋑怿뚘쪈辛展싿䛷뾎ᡂ펙䨍䟅앹ꠃ꠿蚀홞䟭륳ࡓ锁⹦辂킷眈�羚ね☑┃叾Γ昸︟闿哏䪺諿㰍ࣾ○䤱ඍ컵䘍㸬仝軐दꇐၸᬈ햵꺳㪦꡴㳩ṷꅅ꬛ㅊ㜸頨梮藃︉嚱욆箘῕컝릭Ṛ橓웮辉躑룴ᬏ颏閽嫜홷튪ባꭠㅗ㎱r᭢㌃垗ꎙڮ퐑澑昐뢫׏廙朢Ⱁᜌ⼤崐�᛹鋂ࢾ㵝´ﳔ髚ܱ娢玦ᾫ됒뉦ⴇᖞ�⮶橦鐜㏔ピ뚖嫑᫊蓔ꮾᯬ⯩摕듶튆轉즆车쐇哲鄌겷స䝝륁쓚₩幱肇䵊铒솠콊▂꓍Ῠ荧㵦젉턈·ǐ▮鏗梠쭴ﱏ鯺䘢醀ﶼ庘䁊鼌ᑠ鳊碥ﷵ午珰尸盡㹮ﳇ뇌礊䐎狺詈닁复ᆍቿ렗䚪뉚��㘚柭൹䎅딮㚒備慂ﯳꑼ謬윍펺⦌郬눱뫋鿱ţᎎᯉ✋㟰瑈抉앞贎꣍퀧�褙牮蕂監鵣靊ᦆ霎薳蠸ᔴﯿ㪫ㄫ횓�슣藋訢︅錺㿩ⳏ먆�఑꼚Ӿ㓵㌱揝�饀殷㵯嘦Ꝭ춒쥉먤뫝�雸쉞㼜𢡄ᩒ㸊꣤戦锢曍籂瀶葶데롴ᛓﯟ￟룙ھ넼읥濸峈资ை꼒輴�㤭ṤĽ쉾壾曔鬃霚䥴䒍諶타ꗺٿ꺅췈勅༐䲟䢞憵ᩩ話⢗⟒Ꜹ῀ⷾꞹ↤꡻ൠ᪽츌ꛏ癑읃Ⅳൠ꟡꿐䎔냋ࡆ㎇䓵严珰䍈ꏄʇ㏊麂쒭鲍읱렻扰ג鿠�寪ધếߧ�揨互ⓦ斾ᶄ⭡䞅峬䤔ꤙ亗隀毕宜딹ሟ펼먵�鴒⿬헗fi톀薸㵇帱㤏ᐟ䂈Ꭿ矫紦㫅魐뇽⾎账竑쳪澼턳캸ꋏ놞僼㎀ꕉ㷑釯湳﹒㳫麹옳乞幡൥ꭀ밝ֽ࠼꿥꫁Ƚ㄰⩢㕏뢅�堖⭱ꋶ鵹�ﶦ䮟湦첿නᗬⶫ嗦ᘤ⨶灔㵹￞⭂蒎࿑掫䌞쮟楪鼧䥇望鄞嗫葦菡驯嚇ඨ騠踆㫤ꌓ㬆櫥伱渟년뼐聗칕吜諚⵪骼䗛�঄ࠒ௻䃥㠁䚁戇ⵓ밶㕊୒㋕餽㹭䇣짜뷯홃뒠蠿棋姞⮷碽謿Ε㍭ᒚඏ㴄罩⃧죠熣温Ᵽ곛㄃緾孺ސஅ꒳䰽卽䅬혙�診퉛ظ丼㧑표庞옒蔃�닌앻ẇ犹牔♉��ǩ橊★㶷綎玚㦚穷��㴚ꂷ㕒�禐⮜律ꔩ뮕烠㣀᭘飶ꄀ괌곝ု⿫̐⊙ߤᆝᑐ买뙢縬㨭暩ূ⅄㜚篂樷ꓘ൙�츶ྩꤾ鱣䪑猺뜥㼔緧砥朊㕅퓻芧뻶욢쒚Ỵெ窨轷ㇰ굶Ꮡ踝㒩愑⻱贼8윯ࠣ샽掮漵寬湋갔騋飊⭦擺饐柮졙ꪋ䪻ă뇐倨ꟙ笄鸻ࢭ缋꧲흉鏢য়缆栛鶣�ඔ걽痫珉ᩃ榲�䱞㉈됮嚈᭵墵埞폂薋笯뉙㶏鞲뢜鶨ꢾ䡋넥΍┫囧ꄾ繱詿⽱�䚛ꗄ⑽㙫踶鉗ꍲ頻䐑㚕븆顔癪퇸颍洖爤猼ꆇꃱ㱷⨵繀뎬௭朅襴菼욅ہ�ߦϢ籹୰虎銀鏚칉굹ꂺ詖怒荧Օ≃�嵱햠혟艹鋃玕癫䍋淼㎕풡�ԅ⋢㲡质쓞ࣔ┚魜ྎ勣儤䙣㥇�೰훂ᛯ뚚㧢驀�᮵᱔놵Ꟗ�삂ﵜ餜ᠶ㦉퉡䔀場⛋ꉥ꼱⩞ꤿꞇ튙フ楟릐讂Ự쾯谪˂쐷第鑸Ձ缏失�悦㮫㼏ᛎ譪嵰ჵ흤鏈驌㼓퟉ﳖ㑎휋ꈾ滑떎䥤�䊫㮤ᰀ豼ꂋ䍦諷bꇤ謻໬掽ᬍ뽨瀞暵꺳☰␥鵣㯙땯瞻쪄氐뺳纞愍ʛᮍʿ蝙댇娽잲䧠ђ✽拏ㄡ럀钤햓墅鮂ⴇ䩘拁殦귘㶘쉄䇭䘩꿩Ȣ퇢䐇༆侽瀼盉ꭘ⌷ᠿ熌ꚛ䨘왪嵼橾눝ĩĕ鋩䷹晫蓎ꮦ㡯鐾➞ﰞ냏飅젎⑍퓂ꇽ犱⢞ਈ亵ᆭ愀잷絯胚덈諍꺖뎜럞ⶎ瓑嘯줍䚂翜戓翇㜪浼裦-ᕶ뛨行並娂ꥒ뚄贯ꐢĕẈ蛹첾岾�݇ᣄ넺䡑隼嵴笏싌༦瓙ὔሽ꾞疬륰㕑�麥�揓팄갞륨٦櫟큧Ე훼췚煫㎀ﲲ芜均酧೯흇覛粋︌깤잡⸲䔁蕷醍ꨩᬒ岡轡꘤踲픋랸ꑃ녓骨㛑፝ⵈ柢潅ᇄ낗쩽贪糜୶剘텆麦遁䃲誦횥志蓟�밐䉣෰檳꒴洪⍑�盢ᣵ蔁巬蔍췄ꛅ쓿若湥쀍䵘ﻠ鄌雃缬㇢輫颥뀕쎾ᴗ苿ᅧຍ腑춆뱊뵎ᝀ鞙킒�퇩䒔㠖걛땂诬榮꿬㤷覊嵋㦡醃仲䩔嵅嘂Ⴔ♀▙뙴蕒픁ᕭ昑彛딾�ힿ覑葧梒蒍쭅棷芿籧⥛鄫闉⽘칟쉽壪㉏Ń绢뫯堝⣍툍鴺譼舤옶릮꼚�恀ꢽ旽삾욅�䂮詏⟏䜀턺덧鯁燣廮묲扮佁㘦濿㯨�⇻�筈ଏ½㝖③끀農ꕪ鳽睊뵗꿀᰾恤ѹ≪羌࿓㲇痘¡㎇髮뇄ἴ斎룺蕆ᄋ攖傷�騢忰畞Ꙟ�塴⯄倽ﲪꒇ廓ทয়㘿줺죉਼Ѿ⥍ಇ�顸坵ㄢ氼᷎⾖餏렽ⶭ黳糇異಺鄮떔钱钤쵕菁櫪뉖'䦫롎꺔皤濉痠컐퓻펠틧Ẕ㣡聿톘᷆㸾檛�ᛩㆄ�ꖼꫧ둮�ꋽ෰ꬽ♌卋兽⯉�⼀쇰ުLᦋ닳惶췢膢㚚䶊ണ빘)맂㼞︪㗣ㅗ硞畮஭勞�኷䋖酸픫惁솸ﯲ�料Γ텙각诶�τ킸ꭂᶆౙ鷬緎�ﱯ섍퓗㿨䒌틆岯�㍎Ꝥ쵾ᾂ䒥Ë꼱᪲ꍹ橢휬ഴ墲鎗쑌鴆謴ꠚﰿ꧱ቈ烖躋迤⇹鐝抻붇�墈顺먍ꈾ鵢鞑㐻鼮Ỹ幼辱鎖Ⓛᖄ฀㣵❏닒묏굍鋿꫃꺐꧀叻逈閕㛭䎜쮊�櫺凘韡椑ⴱ됣弇瞦왯ཋ芚ᄃ暣牳횞㵺ꢮ垡믆⽯敻쇫쎨醪✨鉅薂퟿匝褤ਮ༷龷᠀䂲烛뗇墕♲钹ᦌ脫商奸軗㧝꼳葯꾏㪐ᒆ쿾ﻭ㚲ꙝ瘣ꍫ麁凷䰤帠ྡྷ鉚쏱캘㰺욶손蟌뜆㸈ᤴ嵧灈ᶌᱹ珨ᕀ귔윥೗及ඔ⣝⌠嶾퉠闏⭸꜋虮엠׵䛏�㓗ꆝ㹾䯨⅕ࠩ㙼嗍Ꞝ䌖͝哻귃砭䑂젒凛쇉阣㗱켏喝�ጫヱ胈䃢ᏹޘ�쇻킱Ḓ�䥗먬﫹獋樘ʍ谹웈ꏿ鮀풃౮䎠맛ᤰ隮䭍㕬쬝ʲᇇ였㍍ክ餏풠Ⓦ걭簡顪繰腁띚،禉�袹疢够挹횕ຖ౱퓦纼蓰葔쩐殨嫓둁˨㫗隢ኚ谙濱ਥ鬱㗤ፓ쪻䒨㛒椎垥錤抪櫱귄㇈抳网ቝറ殙쨋ⵆ㧇䏇街䐹㎩㪚늣轎懘㿺쁨嫞횧릚줱姕�ᖉ峲猋煍蹩ꂥꭏ荿㘇騌ᦃ鶉⎈爽퍲䯸直鞭Ⓡ⤣롽㭸乨썲㤎ꮜ傷藞䧨汱৥寍ƙ䗦툋⥏别櫗䏦෰ꑲ갺䅇똉䪛鰡䘾鵯촻幔䱮欶陛ຝ⾸檜㐳研턛琡멘ޘⲃ힜ふ匢줟葀댸폫䚏㡳뛭憝쫯ᮍ⬺ﴯ笰ڛ콐㼎곴㻦医ꅿ仈涠賲埻柳ﶸ�縧㠎᳕䆩親誱릤妍鼅ბ퀏叉穰堮雬觿ꚴ䶝焤颭ﳟ䎔鶜嫲锬턒㈒뺝⤣�廤ꑵ穈廘郜⡺궳ၘ粗찤梁�믿圂셲璖䬢Ợ厎곑쾞�쁑�癤䴖닆졖�晨劀⩩騚⾴猀В⒫㈣૕룟ꥇ趧�̆楰泣ꁶ䅊珇׏枊﬊䔓噓쒠ﬦ槄帲Ȝ攚霪羥⨐㫳�뷗찝㪓⨼확䰊Ѹ㷿ꦭ﫾潠徘됕睬џ퍐䝷⮪娠땱�䄋诔䴪ᰱᖔ聧樑刚㫡펰횟민嚲ᓖ䰶떩য়ꝢḈ᯶愈⾅ᰥ寥諢擱㷤墴ӧ圻䡋㊐吰䡡ꛣꃘ쁾・藫퉜햽胰姧䚃捏㼻춿虣ᜣ䂽㆐⃐ℶƖ镴뻶ꉌၪ腃굒仱堖痱ꢜײַコ䒨㾦緞놭䧕⊠孔䆄矛㫆핫၂蔿ꥡ늮羴Ԕន망ᙓ䭞㱕铧䬄酙㐞꬟胕颈᧴⠵劫⏯턪耷㰮Ԩ☽㻗뜚�罱釶簥苑뱝᭺㐭藍䗺ⅶ〙鱀䳬痞๭㸨葵됭㯏婊봩媛⑮ᬽ쀩Ⰸ뻄翸䁯ﺞᨶ㆒�鰐칬粃츇Մᚋ嵫온䇨嵺눲韛䕚靶ǻ槳优斋㔏밨儘涪ﴗ᫜

The text encrypted here is taken from a popular website. Good luck guessing which one :). And yes, it decrypts back perfectly!

OK, so how come this is rarely used if it so simple to implement and yet pretty much impossible to break? The problem is sharing the one-time pad — especially for long messages. The security of the one-time pad is precisely its main weakness — it’s way too unwieldy. A 1000-KB message requires a one-time 1000-KB key to be perfectly unbreakable. How do you share a huge key like this without malicious parties intercepting it?

As I had mentioned, spies in the Cold War era actually used this method, but they had much shorter messages to transmit, so their keys needed to be much shorter too. How did they communicate keys? Well, one way to do this was to utilize some publicly available source of randomness — like classified ads.

Another scene from “The Beautiful Mind” — analyzing classified ads.

In one of my favorite movies, The Beautiful Mind, John Nash goes insane trying to analyze and spot patterns in classified ads of different newspapers across the country. Below is a listing of classifieds taken from a 1970s California paper.

Classified ads from 1970s. A corvette for three grand???

How could we use something like this? Well, we could have a agree on a channel — a predefined paper, day and page, even a different column for each day of the week. Then we take classifieds that are posted, and create our random one time pad by converting each word to a number with some simple scheme (see below). What makes classifieds ads superior to generic text (like a poem or the Bible) is the addition of random bits like prices, abbreviations, phone numbers — all interspersed throughout variable length chunks of text. There are some patterns — but they are nearly impossible to detect in one-time pad scheme of encryption where every bit is only used once.

function getWordValue(word) {
var val = 0;

for(var i=0; i< word.length; i++)
val += Math.pow (word.codePointAt (i), i);

return val % UTF_LIMIT;
}

function generateOneTimePad2(wordArr) {
var randArray = wordArr.map(item => getWordValue(item));

var reducer = (accumulator, currentValue) => accumulator + String.fromCodePoint(currentValue);

return randArray.reduce(reducer, "");
}
var keyPart1 = generateOneTimePad2(["Factory", "Meyers", "Manx", "top", "curtain", "Gates", "extras", "Sacrifice", "$1500", "882-2732"]);console.log(keyPart1);>> ♬酩跀ㅰ྿붜ḴᏫ뭽江var keyPart2 = generateOneTimePad2(["'69", "Dune", "Buggy", "green", "metal", "flake", "street", "legal", "best", "offer", "over", "$1200", "805-526-9193"]);console.log(keyPart2);>> ೨\ue866뺖\uf3c2ᭁ늸忶ဢէᇙ쎮멈镾var keyPart3 = generateOneTimePad2(["Chev.", "'67", "Camaro", "SS", "350", "780", "dual", "feed", "Holley", "400", "h.p.", "Z28", "heads", "&", "cam.", "Hedman", "heddlers", "Solids", "Edelbrock", "high", "rise", "manifolds", "American", "mags"]); console.log(keyPart3)>> 資ఈ낭Tशह帊檎﷔ऱ굨౳㝴\u0001ꬄ\udbda빆⸅뚶召\uecbf泀䥽廕
var secretMessage = "Meet corner of Smith 6pm. Package with me";
// length of secret message is 41 chars, length of combined 3 key parts is 48 , we are good to go!var encr = oneTimePadEncrypt(secretMessage, keypart1+keypart2+keypart3);console.log(encr);>> ☡鄌趥㄄ྟ뷿ṛ᎙묓氺ಚ뻹᭡닫徛။ԓᆱ쎎멾锎貪ద낍�ॗग़幡櫯ﶳ॔굈ఄ㜝u꭬�븫⹠
var decr = oneTimePadEncrypt(encr, keypart1+keypart2+keypart3);
console.log(decr);>> Meet corner of Smith 6pm. Package with me

So, there you have it — a secret channel to function as a shared source of randomness, and a one-time pad encryption mechanism. Now, go out and do some spying already!

--

--

Phil_K

Software engineer, entrepreneur, crypto enthusiast — going down rabbit holes, swallowing red pills and looking for the pot of gold at the end of the rainbow…