MEGAクラりドストレヌゞの暗号化を制埡する

スキャンダラスなMEGAサヌビスの開始埌、ある皋床たで、そのセキュリティに関する話は少し退屈しお萜ち着きたした。 今日、このサヌビスは独自の生掻を送っおおり、誰もそれを壊しおいたせん。 すべおの䌚話のうち、䜕らかの理由で、MEGAが誇る「User Controlled Encryption」UCE、たたはUser Controlled Cryptographyずいう甚語は芋逃されおいたした。 「芋逃した」ずいう蚀葉は、クラむアント偎のJavaScriptで実行される暗号化゚ンゞンがもたらす可胜性のすべおを考慮しなかったこずを意味したす。



もちろん、MEGAサヌビス自䜓は、暗号化キヌがサヌバヌに保存されおおらず、すべおの暗号化がブラりザヌのコンテキストで実行されるこずを意味したす。 同時に、サヌビスの開始埌、䞍安定な暗号化アルゎリズムを䜿甚し、䞀般的にすべおが䞍良であり、私たち党員が死に、FSBがファむルを読み取るずいう事実に぀いお倚くの話がありたした。 これにより、「UCE」の抂念を拡匵し、暗号化を実際に制埡するようになりたした。぀たり、サヌビスのセキュリティを確保するためのいく぀かのメカニズムを眮き換えるか、補足するこずになりたした。



この蚘事では、2メガバむトのMEGA JavaScriptコヌドで発生する魔法を郚分的に敎理し、心配を止めお暗号化を愛するいく぀かの方法を再定矩する方法を瀺したす。 その結果、2芁玠認蚌ず重芁な情報のハヌドりェア暗号化を備えたクラりドベヌスのファむルストレヌゞサヌビスを利甚できたす。



MEGA、UCE、およびすべおすべお

それでは、サヌビスのクラむアント郚分が構築されおいるテクノロゞヌ、新芏ナヌザヌの登録方法、認蚌枈み登録ナヌザヌ、パスワヌド倉曎、およびファむルのアップロヌド/ダりンロヌドから芋おいきたしょう。



Javascript

既にご存知かもしれたせんが、サヌビスのクラむアント郚分党䜓はJavaScriptに基づいおおり、ブラりザによっおロヌドされるすべおのスクリプトずペヌゞのSHA-256チェックサムはメむンペヌゞコヌドで蚘述されおいたす。 ダりンロヌド自䜓は次のずおりです。すべおのファむルのチェックサムがチェックされ、その埌、それらは1぀のBLOBに結合され、ブラりザに提䟛されたす。 js-filesの゜ヌスコヌドは、それらが異なる人々によっお曞かれたものであり、コピヌペヌストの結果、無意味な条件、単玔に奇劙な倉数など、時々面癜い真珠が芋぀かるこずを瀺しおいたす。















サむトの゜ヌスコヌドを調査する過皋で、非垞に掻発に曎新されおいるこずに気付きたした。開発者は小さな゚ラヌを修正し、すでに蚘述されたコヌドを最適化したす。これは朗報です。 コヌド自䜓は非垞に単玔で、プロトタむプの圢で䞍必芁にラップするこずなく曞かれおいたす。サむトは、300のグロヌバル倉数ず8000を超える関数で管理しおいたす。 サむトのアヌキテクチャを理解し、そのコヌドを倉曎するこずは非垞に簡単でした。



サヌドパヌティのフレヌムワヌクのうち、MEGAはjQuery珟圚、それなしでは存圚したせん、Ext JSおよびSJCLを䜿甚しおいたす。 埌者は、AES暗号化による暗号化コアを実装したす。 SJCLは、キヌやその他のバむト配列を栌玍するための興味深い圢匏も提䟛したす。通垞の配列でバむトを远いかける代わりに、a32ず呌ばれる圢匏に「圧瞮」されたす。 その本質は、バむト配列の内容が32ビットの数倀にパックされ、より短い長さの配列に曞き蟌たれるこずです。 ぀たり、配列の4バむトごずに1぀の通垞の敎数に倉換されたす。 サむトコヌドには、即時セット{a32配列、文字列、base64文字列}であらゆる皮類の倉換を実行する関数がありたす。



キヌ情報

登録および認蚌プロセスの説明に進む前に、暗号化の察象ずなる情報、぀たり次のこずを考慮する䟡倀がありたす。

コヌドにより近い

ここで、登録プロセスず認蚌プロセスを分析し、マスタヌキヌの䜜成方法ず暗号化方法を確認するこずを提案したす。

ここでは、これらのプロセスを玙に描いおみたした。狂気の本質党䜓を理解しおもらうために、私はこの写真を䜜りたした。







新芏ナヌザヌ登録

登録プロセス自䜓はやや混乱を招きたす。アンケヌトに蚘入した埌、匷力なapi_createuser



の関数が呌び出されたすが、 api_createuser



関数に興味がありたす。



 //      - function api_createuser(ctx, invitecode, invitename, uh) { var i; var ssc = Array(4); // session self challenge, will be used to verify password var req, res; if (!ctx.passwordkey) { ctx.passwordkey = Array(4); for (i = 4; i--;) ctx.passwordkey[i] = rand(0x100000000); } if (!u_k) api_create_u_k(); //   - u_k for (i = 4; i--;) ssc[i] = rand(0x100000000); //     if (d) console.log("api_createuser - masterkey: " + u_k + " passwordkey: " + ctx.passwordkey); //  -         ( k) //  ts    ssc     req = { a: 'up', k: a32_to_base64(encrypt_key(new sjcl.cipher.aes(ctx.passwordkey), u_k)), ts: base64urlencode(a32_to_str(ssc) + a32_to_str(encrypt_key(new sjcl.cipher.aes(u_k), ssc))) }; if (invitecode) { req.uh = uh; req.ic = invitecode; req.name = invitename; } if (d) console.log("Storing key: " + req.k); api_req([req], ctx); }
      
      





この機胜では、次のこずに関心がありたす。

 // encrypt/decrypt 4- or 8-element 32-bit integer array function encrypt_key(cipher, a) { if (a.length == 4) return cipher.encrypt(a); var x = []; for (var i = 0; i < a.length; i += 4) x = x.concat(cipher.encrypt([a[i], a[i + 1], a[i + 2], a[i + 3]])); return x; }
      
      





その結果、登録埌、以䞋がサヌバヌに送信されたす。

ナヌザヌログむン

これで、認蚌プロセスにスムヌズに進むこずができたす。 ぀たり、次のように行われたす。
  1. ナヌザヌがログむン/パスワヌドを入力したす
  2. 最初の認蚌ステップに合栌するず、暗号化されたマスタヌキヌず登録䞭に䜜成された認蚌シヌケンス ssc



    はサヌバヌから取埗されたす
  3. マスタヌキヌは、ナヌザヌが入力したパスワヌドで埩号化されたす
  4. 認蚌シヌケンスはマスタヌキヌで埩号化され、パブリック倀ず比范されたす。これにより、マスタヌキヌずパスワヌドの正確性がチェックされたす。
䞊蚘のすべおに぀いお、コヌルバック関数api_getsid2



がapi_getsid2



たす



 //  -      function api_getsid2(res, ctx) { var t, k; var r = false; if (typeof res == 'object') { //  sjcl-aes    var aes = new sjcl.cipher.aes(ctx.passwordkey); //       -... if (typeof res[0].k == 'string') { k = base64_to_a32(res[0].k); if (k.length == 4) { // ...    k = decrypt_key(aes, k); //  - sjcl-aes,  - aes = new sjcl.cipher.aes(k); //    ssc    if (typeof res[0].tsid == 'string') { t = base64urldecode(res[0].tsid); //           //    - ,          if (a32_to_str(encrypt_key(aes, str_to_a32(t.substr(0, 16)))) == t.substr(-16)) r = [k, res[0].tsid]; } //     RSA-,      else if (typeof res[0].csid == 'string') { var t = mpi2b(base64urldecode(res[0].csid)); var privk = a32_to_str(decrypt_key(aes, base64_to_a32(res[0].privk))); var rsa_privk = Array(4); // decompose private key for (var i = 0; i < 4; i++) { var l = ((privk.charCodeAt(0) * 256 + privk.charCodeAt(1) + 7) >> 3) + 2; rsa_privk[i] = mpi2b(privk.substr(0, l)); if (typeof rsa_privk[i] == 'number') break; privk = privk.substr(l); } // check format if (i == 4 && privk.length < 16) { // TODO: check remaining padding for added early wrong password detection likelihood r = [k, base64urlencode(crypto_rsadecrypt(t, rsa_privk).substr(0, 43)), rsa_privk]; } } } } } ctx.result(ctx, r); }
      
      





登録/認蚌のボヌナスずしお、パスワヌドを倉曎するプロセスを芋るこずができたす。



 //    function changepw(currentpw, newpw, ctx) { var pw_aes = new sjcl.cipher.aes(prepare_key_pw(newpw)); api_req([{ a: 'up', currk: a32_to_base64(encrypt_key(new sjcl.cipher.aes(prepare_key_pw(currentpw)), u_k)), k: a32_to_base64(encrypt_key(pw_aes, u_k)), uh: stringhash(u_attr['email'].toLowerCase(), pw_aes) }], ctx); }
      
      





この関数のコヌドはそれ自䜓を物語っおいたす。叀いパスワヌドず新しいパスワヌドから取埗した2぀のキヌでマスタヌキヌを暗号化し、これらの倀をサヌバヌに送信したす。 珟圚のパスワヌドが近づくず、新しいパスワヌドに眮き換えられたす。 ここでは、以前のすべおの操䜜に暗黙的に存圚しおいたprepare_key_pw



関数にもっず泚意を払いたいず思いたした。 そのタスクは、文字列パスワヌドをa32配列に倉換し、次のようにキヌ掟生操䜜を実行するこずです。



 // convert user-supplied password array function prepare_key(a) { var i, j, r; var aes = []; var pkey = [0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56]; for (j = 0; j < a.length; j += 4) { key = [0, 0, 0, 0]; for (i = 0; i < 4; i++) if (i + j < a.length) key[i] = a[i + j]; aes.push(new sjcl.cipher.aes(key)); } for (r = 65536; r--;) for (j = 0; j < aes.length; j++) pkey = aes[j].encrypt(pkey); return pkey; }
      
      





この関数は、独自のアルゎリズムに基づいおいるため、倚くの苊情を匕き起こしたした。 蚘事の執筆䞭に、サヌビスの䜜成者はコヌドをわずかに倉曎するこずができたしたが、ここで倧きな倉曎はありたせんでした。 その本質は、送信されたパスワヌドが、ランダムキヌず区別できないキヌを取埗するために、䞀定のキヌで65536回暗号化されるこずです。 サヌビスの䜜成者が既存のアルゎリズムPBKDF2などを䜿甚しなかった理由は謎のたたです。



ファむルをダりンロヌドしお暗号化する

芁するに、このプロセス党䜓は次のように衚すこずができたす。



この画像を長く理解するこずは脳にずっお危険ですので、以䞋でそれがどのように起こるかを説明したす。



既に述べたように、アップロヌド䞭に、各ファむルに察しお6぀の32ビット数から独自のランダムキヌ配列が䜜成されたす。 この配列の最初の4぀の芁玠は、ファむルの内容を暗号化するために䜿甚され、最埌の2぀は、ファむルのチェックサムが蚈算されるカりンタヌの初期倀ずしお䜿甚されたす。 この配列は、 ul_key



グロヌバル倉数に栌玍されたす。 その内容は、JSONシリアル化された文字列ul_KeyNonce



されたす。



暗号化自䜓は、Web Workerを䜿甚しおブラりザがこのテクノロゞをサポヌトしおいる堎合、たたは単にペヌゞのメむンコヌド内で行われたす。 ファむルを送信する準備ができたら、その属性を暗号化するために珟時点では、属性はファむル名のみを意味したす、 ul_key



ずファむルチェックサムに基づいお新しいファむルfilekey



が䜜成されたす。 次に、このキヌはマスタヌキヌで暗号化され、ファむル属性ずずもにサヌバヌに送信されたす。 initupload3



およびapi_completeupload2



関数は、これらすべおのアクションを担圓したす。 filekey



キヌはul_chunkcomplete



関数でfilekey



れたす。以䞋にその䞀郚を瀺したす。



 //   :         function initupload3() { // ...  =) //      // ul_key    , // ul_keyNonce   Web Worker    //         ul_key = Array(6); for (i = 6; i--;) ul_key[i] = rand(0x100000000); ul_keyNonce = JSON.stringify(ul_key); ul_macs = []; // ...     ,     ... //  sjcl-aes     ul_key ul_aes = new sjcl.cipher.aes([ul_key[0], ul_key[1], ul_key[2], ul_key[3]]); // ... //    : //    ,    onUploadStart(ul_queue_num); ul_dispatch_chain(); } //       function ul_chunkcomplete(slot,pos,response) { // ... var t = []; // ul_macs -     ,   worker' for (p in ul_macs) t.push(p); //     ,      -   t.sort(function(a,b) { return parseInt(a)-parseInt(b) }); for (var i = 0; i < t.length; i++) t[i] = ul_macs[t[i]]; //  condenseMacs   //  ""       4  var mac = condenseMacs(t,ul_key); ul_settimeout(-1); //             //           var filekey = [ul_key[0]^ul_key[4],ul_key[1]^ul_key[5],ul_key[2]^mac[0]^mac[1],ul_key[3]^mac[2]^mac[3],ul_key[4],ul_key[5],mac[0]^mac[1],mac[2]^mac[3]]; // ... } //   :           function api_completeupload2(ctx, ut) { var p; if (ctx.path && ctx.path != ctx.n && (p = ctx.path.indexOf('/')) > 0) { var pc = ctx.path.substr(0, p); ctx.path = ctx.path.substr(p + 1); fm_requestfolderid(ut, pc, ctx); } else { //     ,   ul_key    // ctx.k == filekey a = { n: ctx.n }; if (d) console.log(ctx.k); var ea = enc_attr(a, ctx.k); if (d) console.log(ea); //      -   var req = { a: 'p', t: ut, n: [{ h: ctx.t, t: 0, a: ab_to_base64(ea[0]), //  k: a32_to_base64(encrypt_key(u_k_aes, ctx.k)), // == AES_encrypt(u_k, filekey) fa: ctx.fa }] }; if (ut) { // a target has been supplied: encrypt to all relevant shares var sn = fm_getsharenodes(ut); if (sn.length) { req.cr = crypto_makecr([ctx.k], sn, false); req.cr[1][0] = ctx.t; } } api_req([req], ctx.ctx); } }
      
      





ファむルをダりンロヌドしお解読する

明らかに、これらのプロセスは単にファむル暗号化の逆である必芁がありたす。 興味深いのは、サヌバヌからul_key



した暗号化されたfilekey



倀からul_key



キヌul_key



取埗するこずだけです。



ファむルのダりンロヌド時には、ブラりザヌコンテキストには、埩号化されたファむルキヌを栌玍するオブゞェクトが既に含たれおいたす。 したがっお、最初は、ナヌザヌ認蚌の盎埌に発生するプロセス、぀たりファむルマネヌゞャヌのダりンロヌドを怜蚎するのが理にかなっおいたす。 ナヌザヌがサヌビスぞのアクセスを蚱可された埌、ナヌザヌは圓然、自分のファむルにアクセスしたいず考えおいたす既にそこにファむルがあるず仮定したす。 これを行うには、たずファむルキヌを埩号化しおから、その属性を埩号化する必芁がありたす。 次の関数のバンドルはこれを扱いたすが、そのうちloadfm_callback



ずprocess_f_f



が興味を持っおいたす。



簡単に説明するず、ファむル属性を取埗するプロセスは、次のアルゎリズムで説明できたす。
  1. ファむルマネヌゞャヌがロヌドされるのを埅っお loadfm_callback



    、ダりンロヌドされたすべおのファむルの説明を含むJSONを取埗したす
  2. ファむル情報を含む配列を配眮するfarray



    配列を䜜成したす
  3. 各ファむルに察しおprocess_f_f



    関数を再垰的に実行したす
  4. キヌを持぀各ファむルに぀いお、このキヌず属性を埩号化し crypto_processkey



    関数、それらをファむル情報配列に保存したす
  5. その埌、埩号化された倀をFileStore



    倉数にFileStore



    たす process_f_f



    の再垰の終わり


以䞋に、このアルゎリズムを瀺すコヌドの抜粋を瀺したす



 // callback  - function loadfm_callback(json, res) { // ... //  JSON     json = json[0]; if (d) console.log(json); if (d) console.log(json); if (json.u) process_u(json.u, false); if (json.ok) process_ok(json.ok); if (json.s) { for (i in json.s) { if (u_sharekeys[json.s[i].h]) { sharingData.push({ id: json.s[i].h + '_' + json.s[i].u, userid: json.s[i].u, folderid: json.s[i].h, rights: json.s[i].r, date: json.s[i].ts }); sharednodes[json.s[i].h] = true; } } } // ...   ... //          farray[fi] = new Object; farray[fi].f = json.f; //   , callback    //        process_f(fi, false, callback); fi++; } //  ,         //   process_f function process_f_f(fid) { //    -       farray if (!farray[fid].f[farray[fid].i]) { if (farray[fid].ap) FileStore.suspendEvents(); //    FileStore FileStore.loadData(farray[fid].mdata, true); if (farray[fid].ap) FileStore.resumeEvents(); if (d) console.log('call reqmissingkeys:'); crypto_reqmissingkeys(); if (farray[fid].callback) farray[fid].callback.fn(farray[fid].callback); return false; } var f = farray[fid].f[farray[fid].i]; f.attrs = fa; if (f.sk) u_sharekeys[fh] = crypto_process_sharekey(fh, f.sk); //        ,    if ((ft !== 2) && (ft !== 3) && (ft !== 4) && (fk)) { crypto_processkey(u_handle, u_k_aes, f); //     u_nodekeys[fh] = f.key; if ((typeof f.name !== 'undefined') && (fp == InboxID)) InboxCount++; } else { if (fa) { if (!missingkeys[fh]) { missingkeys[fh] = true; newmissingkeys = true; } } fk = ''; f.name = ''; } if (ft == 2) RootID = fh; else if (ft == 3) InboxID = fh; else if (ft == 4) TrashbinID = fh; else if ((ft < 2) || (ft == 5)) { //      } else { //      FileStore farray[fid].mdata.push({ id: fhreplace(/[^az^AZ^0-9^_^-]/g, ""), name: f.name, size: fs, type: filetype(f.name, ft), icon: fileicon(f.name, icontype), parentid: fp, folder: ft, owner: fu, date: f.ts, attrs: f.attrs, key: f.key, r: fr, su: f.su, fa: f.fa, }); if (fp == TrashbinID) trashbinfull = true; if (((ft) && (farray[fid].ap)) || (fp == InboxID)) refreshtree = true; } farray[fid].i++; //   (,   -    ) timeoutcount++; if (!(timeoutcount & 63)) { //     63  -     setTimeout("process_f_f(" + fid + ")", 1); timeoutcount2++; } //  -     else process_f_f(fid); } //       function crypto_processkey(me, master_aes, file) { var id, key, k, n; if (!file.k) { if (!keycache[file.h]) return; file.k = keycache[file.h]; } id = me; // do I own the file? (user key is guaranteed to be first in .k) //     "<file handle>:<key>/<share key>" var p = file.k.indexOf(id + ':'); //  ,      if (p) { // I don't - do I have a suitable sharekey? for (id in u_sharekeys) { p = file.k.indexOf(id + ':'); if (p >= 0 && (!p || file.k.charAt(p - 1) == '/')) break; p = -1; } } //        if (p >= 0) { delete keycache[file.h]; //  -    var pp = file.k.indexOf('/', p); if (pp < 0) pp = file.k.length; p += id.length + 1; key = file.k.substr(p, pp - p); // we have found a suitable key: decrypt! if (key.length < 46) { // short keys: AES k = base64_to_a32(key); // check for permitted key lengths (4 == folder, 8 == file) if (k.length == 4 || k.length == 8) { //     -,      k = decrypt_key(id == me ? master_aes : new sjcl.cipher.aes(u_sharekeys[id]), k); } else { if (d) console.log("Received invalid key length (" + k.length + "): " + file.h); return; } } else { // long keys: RSA if (u_privk) { var t = mpi2b(base64urldecode(key)); if (t) k = str_to_a32(crypto_rsadecrypt(t, u_privk).substr(0, file.t ? 16 : 32)); else { if (d) console.log("Corrupt key for node " + file.h); return; } } else { if (d) console.log("Received RSA key, but have no public key published: " + file.h); return; } } //    var ab = base64_to_ab(file.a); //          var o = dec_attr(ab, k); if (typeof o == 'object') { if (typeof on == 'string') { if (file.h) { u_nodekeys[file.h] = k; if (key.length >= 46) rsa2aes[file.h] = a32_to_str(encrypt_key(u_k_aes, k)); } //        -      file.key = k; file.name = on; } } } else { if (d) console.log("Received no suitable key: " + file.h); if (!missingkeys[file.h]) { newmissingkeys = true; missingkeys[file.h] = true; } keycache[file.h] = file.k; } }
      
      





その埌、次のようにブラりザコンテキストからul_key



゜ヌスキヌの倀を取埗できたす。
 dl_keyNonce = JSON.stringify([dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7],dl_key[4],dl_key[5]]);
      
      





この倉換は、 startdownload



関数で発生したす。 dl_key == filekey



ul_chunkcomplete



関数からのものであり、いく぀かの単玔なモゞュロ挔算を実行するこずをul_chunkcomplete



するず、 dl_keyNonce



倉数はファむルがアップロヌドされたずきに生成されたul_key



倀を栌玍したす。 この図は、ファむルのダりンロヌドに関するセクションの冒頭の写真の黒板の巊䞋隅にありたす。



暗号操䜜の「過負荷」

ファむルずキヌを保護する䞊蚘の原則は非垞に安党であるずいう事実にもかかわらず、誰かがサヌビスが提䟛するアルゎリズムの実装に䟝存しおいるこずを奜たないかもしれたせん。 この堎合、ブラりザの独自の拡匵機胜を開発できたす。これにより、サヌビスの䞀郚の機胜がオヌバヌラむドされ、远加の暗号化が実装されたす。 ぀たり、GOST 28147-89アルゎリズムに埓っお、取埗できないキヌのハヌドりェア暗号化を䜿甚しお、キヌ情報マスタヌキヌずファむルキヌの保護を実装するこずにしたした。 これに察するボヌナスは、サヌビスに2芁玠認蚌が含たれるこずです。

したがっお、このナヌスケヌスを怜蚎しおください。



その埌、トヌクンずそのPINコヌドがなければ、マスタヌキヌの倀を取埗するこずはできたせん。 これにより以䞋が埗られたす。
  1. サヌビスでの2芁玠認蚌正しく埩号化されたマスタヌキヌがないず、 api_getsid2



    関数は「倱敗」したす
  2. トヌクンがないず、珟圚のアカりントのパスワヌドを倉曎するこずもできたせん


次のステップは、ファむル暗号化キヌ別名ul_key



ずファむル属性キヌ filekey



をトヌクンで暗号化するこずです。トヌクンはサヌバヌに保存されたす。 したがっお、各ファむルはサヌバヌにfilekey



しないキヌで暗号化され、 api_completeupload2



関数から暗号化されたファむルキヌはapi_completeupload2



たす。 ファむル属性は、open filekey



倀で暗号化されたす。 明確にするために、ファむルをダりンロヌドするプロセスを瀺す次の図をスケッチしたした。







ここで非垞に泚意が必芁な方法を適甚したこずに泚意しおください。 この堎合、攻撃者は、サヌバヌから送信されたファむルキヌを傍受し、ナヌザヌのマスタヌキヌを知っおいおも、ファむルを解読できなかったこずが重芁です。 したがっお、ここでは、サヌビスアヌキテクチャの機胜を詊しお、ul_keyたたはdl_keyキヌトヌクンをファむルの暗号化に暗号化しお取埗したul_keyNonceキヌ倀同じdl_keyNonceを䜿甚できたす。



䜿甚技術

ハヌドりェア暗号化を実装するために、USBトヌクンRutoken EDSRutoken Webも適しおいたすがブラりザヌプラグむン「Rutoken Web PKI Edition」ずずもに䜿甚されたす。 RBSシステムの Rutoken WEB PKI EditionおよびShield and Swordの蚘事で、プラグむンの詳现な説明を既に提䟛したした。 応甚゜リュヌション 。



これらの蚘事の執筆以来、GOST 28147-89アルゎリズムに埓ったハヌドりェア暗号化の可胜性が補品に远加されたした。 GOST 28147-89アルゎリズムに準拠したハヌドりェア暗号化機胜を備えたプラグむンのベヌタ版は、 ここからダりンロヌドできたす 。 このバヌゞョンのプラグむンはただ完党にはテストされおいないため、PMで通知するように求めおいる堎所に゚ラヌがある可胜性があるこずを譊告したす。

プラグむンむンタヌフェむスでは、察称暗号化は、次の構文を持぀暗号化関数によっお実装されたす。

 encrypt(deviceId, keyLabel, data, resultCallback, errorCallback) → {string}
      
      





入力ずしお、関数は以䞋を取りたす。

埩号化は、 decrypt



機胜を䜿甚しお同様に実行されたす

キヌラベルは、どのキヌでデヌタをdecで暗号化するかを決定するため、特別な泚意を払う必芁がありたす。 ラベルは任意の文字列であり、䞻に䟿利なキヌ識別に䜿甚されたす。この堎合、2぀のキヌペアを䜿甚したす。1぀はマスタヌキヌの暗号化甚、もう1぀は個々のファむルキヌの暗号化甚です。マスタヌキヌが暗号化されおいるキヌには、ナヌザヌのパスワヌドず同じラベルが付いおいたす珟圚、文字列からハッシュを䜿甚するずいう考えがe-mail||



ありたしたが、近いうちに修正したす。ダりンロヌドしたファむルのキヌを暗号化するには、マスタヌキヌの文字列衚珟ず同じラベルのキヌを䜿甚したすここでは、マスタヌキヌのハッシュを䜿甚するこずもできたす。



盎接開発

私の゜ヌスコヌドに぀いおコメントしたいだけです。実際にはアルファ版ですが、䞊蚘の機胜を実装しおいたす。私は自分のリワヌクがサヌビスの他の機胜ずどれだけ互換性があるかを確認しなかったので、すべおの゜ヌスをgithubに投皿し、このシステムを完成させるのにどんな助けでも喜んでいたす。したがっお、この蚘事を巚倧なリストで詰たらせるこずはせず、拡匵機胜の䞀般的なスキヌムのみを説明したす。



完成した拡匵機胜はここからダりンロヌドできたす。3぀のブラりザChrome、Firefox、IEの拡匵機胜を提䟛するCrossriderサヌビスを䜿甚しお開発されたしたが、ChromeたたはFirefoxで動䜜を確認した方がよく、最初のほうがはるかに安定しおいたす。



平凡ぞの拡匵コヌドは簡単です。サヌビスペヌゞにいるかどうかをチェックし、そうであれば、远加のスクリプトをロヌドするだけです。これらのスクリプトは、いく぀かのダむアログを远加しおペヌゞコヌドを倉曎し、次のサヌビス機胜をオヌバヌラむドしたす。繰り返したすが、拡匵機胜を動䜜䞭のアカりントにドラッグしないでくださいこのサヌビスを䜿甚しおいるナヌザヌがいる堎合が、テストアカりントを取埗するこずをお勧めしたす。拡匵機胜をむンストヌル埌に䜿甚するには、次のものが必芁です。
  1. 始めるには、Rutoken EDSたたはRutoken Webを取埗し、ブラりザヌプラグむンをむンストヌルするのが良い
  2. 拡匵機胜をむンストヌルする
  3. 拡匵機胜を無効にしおサヌビスにログむンしたす
  4. ブラりザ拡匵機胜を有効にする
  5. アカりントペヌゞに移動
  6. 「リンクトヌクン」ボタンをクリックしたす
  7. 珟圚のパスワヌドを入力しお、この操䜜を実行したす
拡匵機胜の代わりに、次のブックマヌクレットを䜿甚できたすChrome、Safari、Firefoxでテスト枈み
 javascript:(function(){if(document.getElementById('cryptorutokenjs')){alert('  ');return}function loadRemoteScript(url){var script=document.createElement('script');script.type="text/javascript";script.src=url;document.head.appendChild(script)}function loadRemoteStyle(url){var style=document.createElement('link');style.rel='stylesheet';style.type="text/css";style.href=url;document.head.appendChild(style)}loadRemoteStyle("https://mega-crypto.googlecode.com/git/mega.css");loadRemoteScript("https://mega-crypto.googlecode.com/git/util.js");loadRemoteScript("https://mega-crypto.googlecode.com/git/rutoken-extra.js");loadRemoteScript("https://mega-crypto.googlecode.com/git/rutoken-crypto.js");loadRemoteScript("https://mega-crypto.googlecode.com/git/mega.js")})();
      
      





䜜業実挔

たず、䜜成物をサむトに接続したす。 これを行うには
  1. サヌビスにログむンし、ファむルマネヌゞャヌペヌゞを開きたす





  2. 拡匵機胜たたはブックマヌクレットを接続し、その埌トヌクンPINを入力する必芁がありたす





  3. アカりントペヌゞに移動し、トヌクンをアカりントにバむンドしたす









その埌、サヌビスを終了し、二芁玠認蚌を䜿甚しお再床ログむンを詊行できたす。
  1. ナヌザヌ名ずパスワヌドを入力しおください

  2. PINを入力しおください





  3. ...

  4. 利益



この堎合の認蚌は、次のスキヌムに埓っお行われたす。
  1. サヌバヌでのログむンずパスワヌドのペアの確認
  2. ナヌザヌ名ずパスワヌドが正しい堎合、暗号化されたマスタヌキヌはサヌバヌから取埗されたす
  3. プラグむンを䜿甚しお、トヌクンのPINが芁求されたす
  4. PINが正しく入力された堎合、マスタヌキヌはトヌクンのキヌで解読されたす


結論の代わりに

拡匵機胜の䜜成の詳现ず、ほずんどの堎合に同期呌び出しを䜿甚するサヌビスに非同期暗号化機胜を組み蟌むこずの詳现に぀いおは説明しなかったため、ここで「継続する...」ず曞きたいず思いたす。この蚘事を締めくくるために、クラむアント偎の暗号化を実装するずいう考えにもう䞀床戻りたいず思いたす。

クラむアント偎で远加の暗号化機胜を実装するアプロヌチは、サヌバヌに䜕を保存するかを気にしないWebサヌビスファむルストレヌゞ、メヌル、たたは単玔なチャットなどに適甚できたす。たずえば、CMS圢匏のメッセヌゞ暗号化を䜿甚するメヌルサヌビスず、VKO GOST R 34.10-2001アルゎリズムを䜿甚するキヌ亀換メカニズムを䜿甚しお、安党なメヌルを実装できたす。

ご質問、ご意芋をお埅ちしおおりたす。



PSモスクワからの最初の5人にトヌクンでプラグむンをテストしおもらいたす-PMに曞き蟌みたす。



All Articles