質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Q&A

解決済

1回答

4265閲覧

GASでAES暗号化されたファイルをDLし、復号する

thimone

総合スコア1

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

暗号化

ネットワークを通じてデジタルデータをやり取りする際に、第三者に解読されることのないよう、アルゴリズムを用いてデータを変換すること。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

0グッド

0クリップ

投稿2021/07/03 15:43

前提・実現したいこと

GASを使用してDLしたファイルを、そのままGAS上でAES復号化したいです。
DLするファイルはAmazon Selling Partner APIのreport-apiを使用して得られるものです。(DL先URLとkey,ivを与えられている)

発生している問題・エラーメッセージ

復号後の16進文字列が文字にできません。

該当のソースコード

javascript

1const decrypt_test = () => { 2 const url = 'https://tortuga-prod-fe.s3-us-west-2.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.5d4685fe-cdf1-4f37-8dfc-a25b85468e34.T1J5QXLEXAMPLE'; 3 4 const response = UrlFetchApp.fetch(url); 5 const file = response.getContentText(); 6 7 const key = 'xiZ8FGT6pYo49ZwfvAplJxKgO0qW46Morzs5aEXAMPLE'; 8 const iv = 'aoGh0rhbB3ALlCFKiEXAMPLE'; 9 const enc_key = cCryptoGS.CryptoJS.enc.Base64.parse(key); 10 const enc_iv = cCryptoGS.CryptoJS.enc.Base64.parse(iv); 11 const cipherParams = cCryptoGS.CryptoJS.lib.CipherParams.create({ 12 ciphertext: file//cCryptoGS.CryptoJS.enc.Base64.parse(file) 13 }); 14 15 console.log(`enc_key_length:${enc_key.words.length}`); 16 console.log(`enc_iv_length:${enc_iv.words.length}`); 17 18 const decryptedMessage = cCryptoGS.CryptoJS.AES.decrypt(cipherParams, enc_key, { iv: enc_iv, mode: cCryptoGS.CryptoJS.mode.CBC}).toString(); 19 20 console.log(`decryptedMessage:${decryptedMessage}`); 21 22 return decryptedMessage; 23};

output

12021/06/20 20:04:04 debug enc_key_length:8 22021/06/20 20:04:04 debug enc_iv_length:4 32021/06/20 20:04:04 debug decryptedMessage:bfc095f3ecec221e8585ceb68031078d25112f5f26ea2c1f80470f5f4f19f2e1c2cd94638e8666c3486fa29191b568bcd9e8d5a3bdcbbc05456f0567bb6cdae675fa044f94e560379d16b1d370cd7c4a9c5afbbcf4fde2694ed01c1b7950eaabc65e46c4640d8f0814bfe66e8ae65f7768136ac4615624be25373d665ee8fde82742e26664d7c09c61ac8994dc3052f0f22d5042f0b407d696e3c84a3906350dc60c46001ef7865d0c6594c57c5af22616688e028f52d4f12b538d0580c420fdcb0ee61287d4ee2629cd7d39f739d63e84dd75e948eaffb4383076f0c66997

試したこと

・keyとivを文字列のままparseせずセット
・padingをNoneに設定(modeはCBCで合っているはずです)
・responseの変換。getBlob()したりgetBytes()したり
・出力された16進文字列を色々な文字コードでデコード
・Amazonサポートに問合せ→GASで使えそうな情報は貰えず

補足情報

得たいレポートのサンプルとして以下組合せを記載しておきます。

key='xiZ8FGT6pYo49ZwfvAplJxKgO0qW46Morzs5aaOTy5E=' iv='aoGh0rhbB3ALlCFKiuJj6w==' response.getContentText()='������6F��K���wT�"���j҄)�:�՞+��3�8�f��!��¨Ѷd7�g����G��w��ۙ�wxW<���B#CE���p]�R[�!T޽�/ �g`�&���C�8� ��d�;�/T���&�ʳ. U�����j%{�#ՋV-�k���p��B9R��쉒��i]�Wb�' response.getBlob().getBytes()=[-57,18,25,-58,21,-23,-97,27,-38,30,-76,-118,54,70,-101,-74,75,-79,-5,15,-52,119,84,-55,7,34,-11,-65,-85,106,-46,-124,27,41,-77,58,-3,-43,-98,43,-99,-17,51,-78,56,-32,102,-15,-62,33,-97,-25,-88,-62,-88,-47,-74,100,55,-61,24,103,-44,-10,-41,-24,-102,71,-64,-107,119,-24,25,-62,-37,-103,-28,-123,119,120,6,87,60,-97,16,-13,-50,66,35,67,69,-91,-23,-28,-68,30,112,93,28,-54,82,91,-22,26,33,84,-34,-67,-100,47,32,-100,103,96,-99,38,-91,-128,14,-93,67,-26,-88,56,-35,32,4,-9,-86,100,-60,59,-7,47,84,-86,-92,-20,38,26,-21,8,-54,-77,46,11,85,-2,-48,8,-117,-55,14,-24,106,37,123,-80,35,-43,-117,30,86,45,-9,107,30,-93,-28,29,-126,112,-97,-103,66,57,82,-62,-13,-20,-119,-110,-127,-15,-76,105,93,-119,87,98,-28,-100]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

1.ciphertextに渡すデータについて
cCryptoGS(正確には、cCryptoGSがラップしている CryptoJSライブラリ)では、
ciphertextに、WORD配列を含む特別なオブジェクト(「WordArrayオブジェクト」)を渡さなければならないようです。

このために、cCryptoGSには下記のような関数が用意されています。

・cCryptoGS.CryptoJS.enc.Base64.parse(引数:Base64エンコード後の文字列(例:"cXd3aHJpMjNvZyA="))
・cCryptoGS.CryptoJS.enc.Hex.parse(引数:16進文字列(例"4A5F2CDD0B...."))

->それぞれの関数の戻り値は、cCryptoGSが処理可能なWordArrayオブジェクトとなります。

しかし、GAS(js)のバイト列を直接WordArrayオブジェクトに変換するヘルパー関数は見当たらないようです。

したがって、
バイト列 -> 16進文字列 -> enc.Hex.parse() という風に間に1つ噛ませて変換してやればできると思います。

2.レスポンスの処理
元のコードですと、

const file = response.getContentText();

でテキストを得ていますが、これだと変換しにくいので、ここは素直に getBlob().getBytes()でバイト列を直接取得するとよいと思います。
(下記コードでは、バイト列として得たデータを一旦hexes()関数で16進文字列に変換し、
それをenc.Hex.parse()関数でWordArrayオブジェクトに変換してからciphertextに渡しています)

 

3.復号データの取り扱いについて
toString()した復号データは、Shift JISでエンコードされた文字を含むタブ区切りファイルのバイナリを16進数文字列化したものになっています。
したがって、これを直接GAS上で意味のある文字列として表示することはできません。

そこで、
16進文字列 -> Blob化 -> Googleドライブに適当な名前で保存 -> Googleスプレッドシート等でインポート
という流れでデータを復元できます。

下のコードは、Googleドライブの保存まで行っています。

Googleスプレッドシートでのテキストファイルのインポートについては
https://help.loyverse.com/jp/help/how-open-csv-file-google-sheets 参照。

修正(例)

上記を踏まえて質問文を修正すると下記のようになります。
decrypt_test を実行後、エラーがなければ、Googleドライブのルートフォルダに「decrypted.txt」という名前のファイルが作られているはずです。
あとはこれをGoogleスプレッドシートまたはExcel等でテキストインポートすればOKです。

(下記のコードでは、keyやivは”EXAMPLE”を含む文字列のまま修正していませんので、そのままコピペしても正常に復号されないと思います。正しいkey, ivに修正してください。)

GAS

1const decrypt_test = () => { 2 3 // 16進文字列->バイト列 に変換 4 const bytes = (hexstr) => { 5 ary = []; 6 for (var i = 0; i < hexstr.length; i += 2) { 7 ary.push(parseInt(hexstr.substr(i, 2), 16)); 8 } 9 return ary; 10 } 11 12 // バイト列->16進文字列に変換 13 const hexes = (ary) => { 14 return ary.map((e) => ( '00' + (e < 0 ? e += 0x0100 : e).toString(16)).slice(-2)).join('') 15 } 16 17 const url = 'https://tortuga-prod-fe.s3-us-west-2.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.5d4685fe-cdf1-4f37-8dfc-a25b85468e34.T1J5QXLEXAMPLE'; 18 19 const response = UrlFetchApp.fetch(url); 20 // テキストではなくバイト列で取得 21 const file = response.getBlob().getBytes(); 22 23 const key = 'xiZ8FGT6pYo49ZwfvAplJxKgO0qW46Morzs5aEXAMPLE'; 24 const iv = 'aoGh0rhbB3ALlCFKiEXAMPLE'; 25 const enc_key = cCryptoGS.CryptoJS.enc.Base64.parse(key); 26 const enc_iv = cCryptoGS.CryptoJS.enc.Base64.parse(iv); 27 const cipherParams = cCryptoGS.CryptoJS.lib.CipherParams.create({ 28 // バイト列を16進文字列に変換し、さらにwordarrayオブジェクトに変換する。 29 ciphertext: cCryptoGS.CryptoJS.enc.Hex.parse(hexes(file)) 30 }); 31 32 console.log(`enc_key_length:${enc_key.words.length}`); 33 console.log(`enc_iv_length:${enc_iv.words.length}`); 34 35 const decryptedMessage = cCryptoGS.CryptoJS.AES.decrypt(cipherParams, enc_key, { iv: enc_iv, mode: cCryptoGS.CryptoJS.mode.CBC}).toString(); 36 37 console.log(`decryptedMessage:${decryptedMessage}`); 38 39 //return decryptedMessage; 40 // 復号データをバイナリ化し、「decrypted.txt」という名前でドライブのルートディレクトリに保存する。 41 const bin = bytes(decryptedMessage) 42 const myBlob = Utilities.newBlob(bin, MimeType.TEXT, "decrypted.txt"); 43 DriveApp.createFile(myBlob); 44}

 


(参考) 動作検証コード

(decrypt_test2を実行すると、Googleドライブのルートフォルダに「test_decrypt.txt」という名前のファイルが作られます)

GAS

1 2const decrypt_test2 = () => { 3 4 // 16進文字列->バイト列 に変換 5 const bytes = (hexstr) => { 6 ary = []; 7 for (var i = 0; i < hexstr.length; i += 2) { 8 ary.push(parseInt(hexstr.substr(i, 2), 16)); 9 } 10 return ary; 11 } 12 13 // バイト列->16進文字列に変換 14 const hexes = (ary) => { 15 return ary.map((e) => ( '00' + (e < 0 ? e += 0x0100 : e).toString(16)).slice(-2)).join('') 16 } 17 18 const bdata = [-57,18,25,-58,21,-23,-97,27,-38,30,-76,-118,54,70,-101,-74,75,-79,-5,15,-52,119,84,-55,7,34,-11,-65,-85,106,-46,-124,27,41,-77,58,-3,-43,-98,43,-99,-17,51,-78,56,-32,102,-15,-62,33,-97,-25,-88,-62,-88,-47,-74,100,55,-61,24,103,-44,-10,-41,-24,-102,71,-64,-107,119,-24,25,-62,-37,-103,-28,-123,119,120,6,87,60,-97,16,-13,-50,66,35,67,69,-91,-23,-28,-68,30,112,93,28,-54,82,91,-22,26,33,84,-34,-67,-100,47,32,-100,103,96,-99,38,-91,-128,14,-93,67,-26,-88,56,-35,32,4,-9,-86,100,-60,59,-7,47,84,-86,-92,-20,38,26,-21,8,-54,-77,46,11,85,-2,-48,8,-117,-55,14,-24,106,37,123,-80,35,-43,-117,30,86,45,-9,107,30,-93,-28,29,-126,112,-97,-103,66,57,82,-62,-13,-20,-119,-110,-127,-15,-76,105,93,-119,87,98,-28,-100]; 19 const key='xiZ8FGT6pYo49ZwfvAplJxKgO0qW46Morzs5aaOTy5E='; 20 const iv='aoGh0rhbB3ALlCFKiuJj6w=='; 21 const cipherParams = cCryptoGS.CryptoJS.lib.CipherParams.create({ 22 ciphertext: cCryptoGS.CryptoJS.enc.Hex.parse(hexes(bdata)), 23 }); 24 const enc_key = cCryptoGS.CryptoJS.enc.Base64.parse(key); 25 const enc_iv = cCryptoGS.CryptoJS.enc.Base64.parse(iv); 26 const dec = cCryptoGS.CryptoJS.AES.decrypt( 27 cipherParams, 28 enc_key, 29 {iv: enc_iv, mode: cCryptoGS.CryptoJS.mode.CBC } 30 ).toString(); 31 32 33 // 16進文字列をバイナリ化しファイルとして保存 34 const bin = bytes(dec); 35 const myBlob = Utilities.newBlob(bin, MimeType.TEXT, "test_decrypt.txt"); 36 DriveApp.createFile(myBlob); 37}

生成された「test_decrypt.txt」をGoogleスプレッドシートでインポートした例(画像)
イメージ説明

投稿2021/07/04 14:00

編集2021/07/04 16:26
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thimone

2021/07/05 13:03

丁寧なご説明と動作検証までしていただき、ありがとうございます。 頂いたコードで、確かに復元後のファイルが手に入りました。 期間にして1ヶ月くらい悩んでいたのですが、解決してほっとしました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問