QuizKnockの「サマーウォーズの暗号、ガチで解けるかやってみた」の第一問の解読機を作ってみた

# 完成図
Alphabet Cryptanalyzer
https://alphabet-cryptanalyzer.netlify.app/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484621/7e51cac2-a7a3-af33-5476-3580e032c266.png)

# 目次
[1.はじめに](#はじめに)
[2.つくったキッカケ](#つくったキッカケ)
[3.制作物](#制作物)
[4.テンプレート内](#テンプレート内)
[5.スクリプト内](#スクリプト内)
[6.復号化](#復号化)
[7.暗号化](#暗号化)
[8.最後に](#最後に)

#はじめに
大学生のちょこっと開発をした記事です。正確性は保証しません。
一発ネタと思ってお読み下さい。

大学4年の夏、暇を持て余しつつゴロゴロしながらYoutubeを見ていたところ、QuizKnockの「サマーウォーズの暗号、ガチで解けるかやってみた【RSA暗号】」という動画を観ました。

ちょうど金曜ロードショーでサマーウォーズを観る前だったので、観ながら「ここ、QuizKnockで見たところだ！」とか「健二やばすぎ」といった感じで観ることが出来ました。観るのは三回目くらいだったのですが、なかなか新鮮な視点を持てるもんですね。

まだの方はぜひ動画視聴後にサマーウォーズを観てみて下さい。きっと二倍楽しめます。

https://www.youtube.com/watch?v=kvC55N4k9ng

# つくったキッカケ
ここから本題なのですが、この動画中に導入としてアルファベットを順番で数値化する、という規則の暗号が出てきます。これ自体はとても単純なものだと思います。

`a　→　01`
`b　→　02`
…
`y　→　25`
`z　→　26`

といった形です。

後日、同じくQuizKnock好きの彼女から突如 **暗号化されたLINE** が送られてきました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484621/7832ba15-d265-d1fc-a2a7-360429a825a1.png)
普通に頑張って解くのもなんかシャク…！ということで、今回は最近絶賛勉強中の`Vue.js`を使って

- 暗号→アルファベット
- アルファベット→暗号

の相互変換が出来るツールを作成してみました。
Javascriptもまともに触ったのは最近なので、ちょっとは勉強しなきゃなあ…と思っていい機会になりました。

# 制作物
↓実際に暗号化と復号化できます！
Alphabet Cryptanalyzer
https://alphabet-cryptanalyzer.netlify.app/

GitHub
https://github.com/Sidrami/Quizknock-Cryptanalyzer

# 利用するソフトウェア

1. Vue.js v2
1. Vue-cli

# テンプレート内
今回はVue-cliで作ったときについてくるApp.vueを一部改変して作ってみました。

```Vue
<template>
  <div id="app">
    <h1>復号化</h1>
    <h2>1111... to text</h2>
    <input v-model="inputForDecrypt" />
    <button @click="quizKnockDecrypt">decrypt!</button>
    <h1>{{ resultDecrypt }}</h1>
    <h1>暗号化</h1>
    <h2>text to 1111...</h2>
    <input v-model="inputForEncrypt" />
    <button @click="quizKnockEncrypt">encrypt!</button>
    <h1>{{ resultEncrypt }}</h1>
  </div>
</template>
```


シンプルに、`input`と`button`だけで作っています。上がもともと私が必要としてた復号化部分、下が返信のために作った暗号化部分になります。

それぞれに入力してボタンを押すと、`methods`で定義された関数が実行されるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484621/47fb0595-8523-eae4-6b0e-fbad8891f76b.png)

# スクリプト内
続いて、スクリプトタグ内です。全体像はこんな感じ。

```Vue
<script>
export default {
  name: "App",
  data: function () {
    return {
      inputForEncrypt: "",
      inputForDecrypt: "",
      resultEncrypt: "",
      resultDecrypt: "",
      alphabet: "abcdefghijklmnopqrstuvwxyz",
    };
  },
  methods: {
    quizKnockDecrypt() {
      const input = this.inputForDecrypt;
      const alpha = this.alphabet;
      let result = [];
      for (let i = 0; i < input.length; i += 2) {
        result.push(input.substring(i, i + 2));
      }
      console.log(result);
      result.forEach(function (value, index) {

        result[index] = alpha[value - 1].toUpperCase();
      });
      this.resultDecrypt = result.join("");
    },
    quizKnockEncrypt() {
      const input = this.inputForEncrypt.toLowerCase();
      const alpha = this.alphabet;
      let result = "";
      result = input.split("");
      result.forEach(function (value, index) {
        let num = alpha.indexOf(value) + 1;
        num = ("00" + num).slice(-2);
        result[index] = num;
      });
      this.resultEncrypt = result.join("");
    },
  },
};
</script>
```

それぞれの部分に関して見ていきます。

`data`内

```javascript
  data: function () {
    return {
      inputForEncrypt: "",
      inputForDecrypt: "",
      resultEncrypt: "",
      resultDecrypt: "",
      alphabet: "abcdefghijklmnopqrstuvwxyz",
    };
  },
```

`input〜〜`はそれぞれの入力値をバインディングしてます。
また、`result〜〜`はそれぞれのメソッドで出力する値を格納。
`alphabet`には、今回の暗号のアルゴリズム上で使うために文字列として全アルファベットを順番に入れてあります。

# 復号化
全体像はこんな感じ。

```javascript
// 復号化用
    quizKnockDecrypt() {
      const input = this.inputForDecrypt;
      const alpha = this.alphabet;
      // 答え格納用配列
      let result = [];
      // Stringから2文字ずつ文字を取得
      for (let i = 0; i < input.length; i += 2) {
        result.push(input.substring(i, i + 2));
      }
      // 各2桁の数字に対して処理を実行
      result.forEach(function (value, index) {
        // alphabetの羅列からindexを取得
        // 見た目的に大文字にしてみました
        result[index] = alpha[value - 1].toUpperCase();
      });
      // 完成した配列を出力用に結合
      this.resultDecrypt = result.join("");
    },
```
まず、`data`から必要なデータを取得しています。

```javascript
const input = this.inputForDecrypt;
const alpha = this.alphabet;
// 答え格納用配列
let result = [];
```

そして、`input`を2文字ずつに区切ります。

```javascript
for (let i = 0; i < input.length; i += 2) {
    result.push(input.substring(i, i + 2));
}
```

`input`が`11221322`なら、配列として`11,22,13,22`といった具合に分けられました。

参考

https://qiita.com/turmericN/items/0819317b5c075d971bfa

あとは、`forEach`を使ってそれぞれの数字に当てはまるアルファベットに変換するだけ。
今回は`alpha`内に先程の`abcde...xyz`が入っているので、それぞれの数字から1を引いて`alpha`の`index`と照合しています。

また、出力は大文字のほうが見た目がキレイだったので`toUpperCase()`で大文字にしています。

```javascript
// 各2桁の数字に対して処理を実行
result.forEach(function (value, index) {
  // alphabetの羅列からindexを取得
  // 見た目的に大文字にしてみました
  result[index] = alpha[value - 1].toUpperCase();
});
// 完成した配列を出力用に結合
this.resultDecrypt = result.join("");
```

以上で復号化部分は完成です。
みなさんもぜひLINEで暗号化された数字が送られてきたら復号化してみてください。

でもやっぱり、暗号で送られてきたら暗号で返したいですよね。
暗号化をするメソッドも紹介します。

# 暗号化
全体像はこんな感じ。

```javascript
quizKnockEncrypt() {
  // 入力が大文字だとマッチしないので、小文字に変換
  const input = this.inputForEncrypt.toLowerCase();
  const alpha = this.alphabet;
  let result = "";
  // 入力値を配列に変換
  result = input.split("");
  // 各アルファベットに対して処理を実行
  result.forEach(function (value, index) {
    // 今回の暗号はaが1始まりのため、プラス1
    let num = alpha.indexOf(value) + 1;
    // 1桁の数字は0*と表記されるため、補完
    num = ("00" + num).slice(-2);
    result[index] = num;
  });
  // 出力用に結合
  this.resultEncrypt = result.join("");
},
```

ここらへんは復号化と似ていますが、今回は`input`が小文字でないと動かない（`alphabet`の定義が小文字）ので、`toLowerCase()`を利用しています。

```javascript
// 入力が大文字だとマッチしないので、小文字に変換
  const input = this.inputForEncrypt.toLowerCase();
  const alpha = this.alphabet;
  let result = "";
  // 入力値を配列に変換
  result = input.split("");
```

そして、復号化と同じく`forEach`で入力された値全てに数字へ変換する処理を実行していきます。

今回の暗号は`a → 01`なので、最初にプラス1する必要があります。
`alphabet`のindexにプラス1しています。

そして、1桁の数字は0が先頭につくため、補完します。

```javascript
// 各アルファベットに対して処理を実行
  result.forEach(function (value, index) {
    // 今回の暗号はaが1始まりのため、プラス1
    let num = alpha.indexOf(value) + 1;
    // 1桁の数字は0*と表記されるため、補完
    num = ("00" + num).slice(-2);
    result[index] = num;
  });
  // 出力用に結合
  this.resultEncrypt = result.join("");
```

参考

https://zenn.dev/tk4/articles/296cc086d8fdb616214f

これで、暗号化することもできますね。お疲れさまでした！

# 最後に
今回、日常のLINEからちょっとコード書こう！となったのですが、こういうモチベは一番大事な気がします。
特にフロントエンドなんてアウトプットしやすいので、また今回のような形で制作していこうかなと思います。

まだまだ未熟な部分しかありませんので、ここはまずくない？という点や指摘などいただけるようでしたら非常に助かります！

繰り返しにはなりますが、QuizKnockさんの動画、非常に面白いのでぜひ見てみて下さい！このような形で学びを与えてくれるチャンネルは中々ありません！（ステマとかではなく、私は部外者です）

https://www.youtube.com/watch?v=kvC55N4k9ng