エスケープ文字が入った文字列のハッシュをとるときの注意点


shellで文字列のハッシュをとるときにechoコマンドを使用しますが、エスケープ文字が入っている場合の注意事項です。
勉強がてらAWS 署名バージョン4を自分で計算するスクリプトを書いていた時に遭遇したので、そのメモ書きになります。
署名アルゴリズムに関しては上記リンクを参照してください。

遭遇した事象

シグネチャを生成する時に正規リクエスト(メソッドやヘッダなどを\nでつなげたもの)のハッシュが必要になります。このとき、次のような文字列を生成してハッシュをとる操作をしました。

CANONICAL_REQUEST="${METHOD}\n${CANONICAL_URI}\n${CANONICAL_QUERY_STRING}\n${CANONICAL_HEADERS}\n${SIGNED_HEADERS}\n${REQUEST_PAYLOAD}"
HASHED_CANONICAL_REQUEST=`echo -n ${CANONICAL_REQUEST} | openssl dgst -sha256 | awk '{print $2}'`

ところが、この操作を経由して生成されたシグネチャが通らず。
当時はここが悪いと考えておらず、問題個所の特定に苦労しました…

原因と解決策

echoコマンドはデフォルトでエスケープ文字を解釈しない(=-Eオプションをつける)設定になっています。AWSの署名の場合はエスケープ文字を解釈する必要があるので、-eオプションをつけてエスケープ文字を解釈させましょう。
次の例ではエスケープ文字を解釈する/しないによってハッシュが変わることがわかりますね(当然ですが)。

$ TEXT="hoge\nfuga"
$ echo -n ${TEXT} | openssl dgst -sha256 | awk '{print $2}'
074659bf99be27ea41e727fda69060e866fe4fd0ab0fab5bd6dc1fb24a4ad246
$ echo -E -n ${TEXT} | openssl dgst -sha256 | awk '{print $2}'
074659bf99be27ea41e727fda69060e866fe4fd0ab0fab5bd6dc1fb24a4ad246
$ echo -e -n ${TEXT} | openssl dgst -sha256 | awk '{print $2}'
91601213bfcbda65e36673d1c92b6306f548cd196117682594715a11c5b6e671
$ 

これで認証が通るようになりました。
生成されたハッシュが正しいかどうかの確認はサンプルでも持っていない限り大変なので、同じ事象に遭遇した人に少しでもヒントになればと思った次第です。事象としては何も難しいことはありませんが、署名アルゴリズムなどのようにハッシュが必要になる場合は注意が必要ですね。