おしりんブログ

新人PGおしりんの色々まとめるよブログ

SHA! えびばーでぃ!

こんばんちょ。

さっきふと、自分のtwitterIDで検索かけたら
どんな検索結果が出てくるのかな?と思い、

ぐぐってみました。

f:id:shiori_west:20140721235226p:plain

青春フルパワーで、うっきゅ~!!!!!!!
二年前も頭の悪さは相変わらずでした。


ところで先週、文字列をハッシュ関数するメソッドとか、
エンコード(暗号化)するメソッドを作ったよ。(唐突)

具体的には

SHA-1するメソッド
・HmacSHA-256するメソッド
Base64エンコードするメソッド

このみっつ。(「SHA-?する」って表現でいいのかな)


今日はこの3つのメソッドについて、
またそれに関連する各用語について少しまとめたいと思うよ。


それでは。

・SHAとは
 Secure Hash Algorithm(セキュアハッシュアルゴリズム)のこと。
 
 一群の関連したハッシュ関数であり、
 アメリカ国立標準技術研究所 (NIST) によって
 アメリカ政府標準のハッシュ関数として採用されている。(Wiki引用)

 現在、SHAは
 「SHA-0」「SHA-1」「SHA-2」「SHA-3」の4種類が存在している。


通信する時のセキュリティを強化するために、
通信したい情報をぱっと見で分からない形に変える方法の一つがSHAって認識~

(恒例:うまくまとまらない)


では次に。

SHA-1とは
 認証やデジタル署名などに使われるハッシュ関数のひとつ。
 2の64乗ビット以下の原文から160ビットの「ハッシュ値」を生成し、
 通信経路の両端で比較することで、
 通信途中で原文が改ざんされていないかを検出することができる。
 
 SHA-1はもっともよく使われる関数であり、
 さまざまなセキュリティのアプリケーションやプロトコルに採用されている。

 計算方法には初期値敏感性の不可逆な一方向関数を含むため、
 ハッシュ値は擬似的な乱数のような値をとり、
 これをもとに原文を再現することはできない。
 (引用元:http://e-words.jp/w/SHA-1.html


・SHA-2とは
 任意長の原文から固定長の特徴的な値である
 「ハッシュ値」を求める計算手順(アルゴリズム)の標準規格の一つ。
 
 「SHA-224」「SHA-256」「SHA-384」「SHA-512」
 の4つをまとめた総称。
 
 末尾の数字がそれぞれのハッシュ値のビット長を表しており、
 一般的にはSHA-256が最もよく利用されている。
 (引用元:http://e-words.jp/w/SHA-2.html


ハッシュ関数の種類だね~
用途に応じてどのハッシュ関数に変換するか決めるみたい。

ちなみに
いちばんセキュリティ安全性が高いのはSHA-512

ハッシュ関数化のパターンとしては
2の512乗 通りのハッシュ値をとるんだって。

約1.341×10の154乗
154乗ってなんぞや。


用語の説明はこんなもんにして、
メソッドお披露目~じゃーん。まずはSHA-1メソッドから。

/**
 * SHA1化する
 *
 * @param str
 * @return SHA1化した文字列
 */
public static String toSHA1(String str) {
  MessageDigest digest;
  try {
    digest = MessageDigest.getInstance("SHA-1");
  } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
  }

  byte[] sha1;
  try {
    sha1 = digest.digest(str.getBytes("UTF-8"));
  } catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e);
  }
  return new String(Hex.encodeHex(sha1));
}

してますね~SHA-1

最後に文字列を16進数化 Hex.encodeHex(sha1)してるのは、
ハッシュキーの長さが16進数で表されてるから?

なんで16進数化するんですかって聞いた気がするけど
忘れてもーた。モーゼの墓。(?)

あした確認しよ。


つぎにSHA-256化メソッド

/**
 * SHA256化する
 *
 * @param str
 * @return SHA256化した文字列
 */
public static String toSHA256(String str) {
  MessageDigest digest;
  try {
    digest = MessageDigest.getInstance("SHA-256");
  } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
  }

  byte[] sha256;
  try {
    sha256 = digest.digest(str.getBytes("UTF-8"));
  } catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e);
  }
  return new String(Hex.encodeHex(sha256));
}

はい、何が変わったって
MessageDigest.getInstance("SHA-1")の部分が
MessageDigest.getInstance("SHA-256")に変わっただけだよ。


ふっつーーにSHA-?化するのは簡単っていうか
結構色々なサイトに方法(ソース)が乗っかってるから、
それを参考にすればいいんだけど、

今回のミッション、実は
「指定された公開鍵を使ってSHA-256化するんやで」だったんですよ。

これがなかなかネット上に方法が乗っかってなくて
ミッションコンプリーツに苦労しました。

しかも結局先輩が参考になりそうなサイトを見つけてくれて、
それを見ながらコードを書いたっていう。


じまさんダメダメじゃないっすか。
ダメダメじまさんですよ。

そんな感じで完成したSHA-256化メソッドfeat.公開鍵がこちら。

/**
 * HmacSHA256化する
 *
 * @param target 暗号化したい文字列
 * @param key 公開鍵
 * @return HmacSHA256エンコード化した文字列
 */
public static String toHmacSHA256(String target, String key) {

  byte[] result;
  try {
    SecretKeySpec sk = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");

    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(sk);
    result = mac.doFinal(target.getBytes("UTF-8"));
  } catch (Exception e) {
    throw new RuntimeException();
  }
  return new String(Hex.encodeHex(result));
}

HmacSHA256って誰だおまえーーー

って感じだけど、とにかく公開鍵を使って暗号化するときは
java.security.MessageDigestじゃなくて、
javax.crypto.Macっていうのを使うんだって。

new SecretKeySpecすることで、
ただの文字列として渡ってきた鍵を、「公開鍵」として
使える状態に復元するところから始めなきゃいけないんだって。

で、Macさんにnew SecretKeySpecした公開鍵を渡してあげて、
doFinalでSHA-256化してもらう。的な流れ。


ヒェーーーうまくまとまらない。


そういえば、公開鍵ってそもそもなんだよ!唐突に出てきたな!
って感じなので、さらっと公開鍵についても触れる。

公開鍵暗号とは
 対になる2つの鍵を使ってデータの暗号化・復号を行う暗号方式。

 公開鍵暗号では暗号化に使う鍵と復号に使う鍵が分離されており、
 公開鍵で暗号化されたデータは秘密鍵でしか復号することができない。
 
 鍵の持ち主は復号に使う鍵のみを他人に知られないように管理し、
 暗号化に使う鍵は公開する。
 
 このため、暗号化に使う鍵は公開鍵復号に使う鍵は秘密鍵と呼ばれる。
 (引用元:http://e-words.jp/w/E585ACE9968BE98DB5E69A97E58FB7.html


これまたセキュリティ強度を上げる方法の一つですな。


最後にもういっちょ、セキュリティ強化の仕上げに
Base64エンコーディングもかけますか。

/**
 * Base64エンコードする
 *
 * @param sha256
 * @return Base64エンコード化した文字列
 */
public static String toBase64(String sha256) {
  byte[] encodedBytes;
  String result;
  try {
    encodedBytes = Base64.encodeBase64(sha256.getBytes("UTF-8"));
    result = new String(encodedBytes, "UTF-8");
  } catch (UnsupportedEncodingException e) {
    // 通常ありえない
    throw new RuntimeException();
  }
  return result;
}

もうづかれだ。ねむい。

最後に。importしたのはこのひとたち。
本番環境では上のメソッドたちは一つのクラスにまとまってるよ。

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

あとあれ。現場では、
Sha256化した文字列をさらにBase64エンコーディングしていたよ。


…なんかまた微妙な記事を投稿してしまった。
三連休終わってしまった。

明日からもがんばるどおおおおおおおドドドド
なにするんだろ。
おやスヤァ。