はてなのWSSE認証をC#で実装してみた
プログラムで撮影した自分のコスプレ写真など、はてなフォトライフにプログラムからアップロードするには、はてなのWeb APIを使用する必要があります。*1 はてなのWeb APIを使用するには、WSSE認証が必要なので、そのC#実装をまとめます。
http://developer.hatena.ne.jp/ja/documents/auth/apis/wsse
概要
はてなのユーザIDとパスワードからWSSE認証のヘッダを生成するライブラリ。*2
WSSE認証とは
要は、Basic認証は、ユーザ名とパスワードが平文でサーバーに送られてしまうから、脆弱だお。だから、ダイジェスト認証の一つのWSSE認証を使うんだお!ってことでしょ?たぶん。
HatenaAccount.cs
using System; using System.Security.Cryptography; using System.Text; namespace Harunakasoft.Library { public class HatenaAccount { /// <summary> /// コンストラクタ /// </summary> /// <param name="userName">ユーザ名</param> /// <param name="password">パスワード</param> public HatenaAccount(string userName, string password) { #if DEBUG logger.Debug("はてなアカウント UserName=" + userName); logger.Debug("はてなアカウント Password=" + password); #endif if (userName == null) { throw new ArgumentNullException("ユーザ名がNULL"); } if (userName.Length == 0) { throw new ArgumentException("ユーザ名が空"); } if (password == null) { throw new ArgumentNullException("パスワードがNULL"); } if (password.Length == 0) { throw new ArgumentException("パスワードが空"); } header = MakeWSSEHeader(userName, password); logger.Info("はてなアカウントヘッダ作成完了"); logger.Info(" header=" + header); } /// <summary> /// WSSEヘッダの作成 /// </summary> /// <param name="userName">ユーザ名</param> /// <param name="password">パスワード</param> /// <returns>WSSEヘッダ</returns> private string MakeWSSEHeader(string userName, string password) { DateTime created = new DateTime(DateTime.Now.Ticks); string nonce = GenNounce(40); byte[] nonceBytes = Encoding.ASCII.GetBytes(nonce); string nonce64 = Convert.ToBase64String(nonceBytes); string digest = GenDigest(password, created, nonce); string createdString = created.ToString("s"); string header = string.Format( @"UsernameToken Username=""{0}"", PasswordDigest=""{1}"", Nonce=""{2}"", Created=""{3}""", userName, digest, nonce64, createdString); return header; } /// <summary> /// Digestの作成 /// </summary> /// <param name="password">パスワード</param> /// <param name="created">作成日時</param> /// <param name="nonce64">Nonce</param> /// <returns>Digest</returns> private string GenDigest(string password, DateTime created, string nonce) { byte[] digest; using (SHA1Managed sha1 = new SHA1Managed()) { string digestText = nonce + created.ToString("s") + password; byte[] digestBytes= Encoding.ASCII.GetBytes(digestText); digest = sha1.ComputeHash(digestBytes); } string digest64 = Convert.ToBase64String(digest); return digest64; } /// <summary> /// Nonceの作成 /// </summary> /// <param name="length">Nonce長</param> /// <returns>Nonce</returns> private string GenNounce(int length) { RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider(); byte[] buffer = new byte[length]; rnd.GetBytes(buffer); string nonce64 = Convert.ToBase64String(buffer); return nonce64; } /// <summary> /// ヘッダ /// </summary> public string WSSEHeader { get { return header; } } private readonly string header; private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); } }