JAVA端:
byte[] iv = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
private String encrypt(String plaintext, String key){
String ret ="";
try{
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec spec = new SecretKeySpec( key.getBytes(), "AES");
cipher.init( Cipher.ENCRYPT_MODE, spec, paramSpec);
byte[] encryptData = cipher.doFinal(plaintext.getBytes());
ret = ByteTransfer.toHex(encryptData);
}
catch (Exception e)
{
e.printStackTrace();
}
return ret;
}
Silverlight端:
private string decryptAES_Silverlight(string encryptedContent)
{
string AES_key = MY_KEY;
byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
string decryptedContent = "";
byte[] b_encryptedContent = HexStrToByteArray(encryptedContent);
AesManaged aes = new AesManaged();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Padding = PaddingMode.PKCS7;
aes.Key = UTF8Encoding.UTF8.GetBytes(AES_key);
aes.IV = iv;
ICryptoTransform decryptTrans = aes.CreateDecryptor();
MemoryStream decryptStream = new MemoryStream();
CryptoStream decryptor = new CryptoStream(decryptStream, decryptTrans, CryptoStreamMode.Write);
decryptor.Write(b_encryptedContent, 0, b_encryptedContent.Length);
decryptor.FlushFinalBlock();
//解密後的byte[]
byte[] decryptBytes = decryptStream.ToArray();
decryptedContent = UTF8Encoding.UTF8.GetString(decryptBytes);
return decryptedContent;
}
Note:
1. 看起來JAVA的預設應該是使用Rijndael,不需要設定Initialization Vector;只是Silverlight端不支援Rijndael,而AES的另一個class - AESManaged卻必須設定IV,為了配合在Silverlight使用AESManaged類別,所以在JAVA加密端也要加入IV的設定。
2. Cipher.getInstance()內若不傳入參數,預設應該是AES/ECB/NoPadding;AES/CBC/PKCS5Padding的設定是為了配合Silverlight端,因為AESManaged只能用CBC mode;至於padding的部分,因為要加密的資料不一定會是16 bytes的倍數,padding就少不了了,JAVA端設定PKCS5,C#端相對的必須設定PKCS7,這兩個mode運作方式在此情況下是一樣的。
3. JAVA端的String.getBytes()若不指定Encoding,預設應該為UTF-8或ISO-8859_1(此處看來是UTF-8),在silverlight端必須將Key以及解碼結果的byte陣列也做UTF-8的編碼處理。
4. HexStrToByteArray、ByteTransfer.toHex()方法均為另外寫的十六進位陣列轉換。
Café de La Mer
2013年7月30日 星期二
2013年6月3日 星期一
程式Memo - C# HTTP POST
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Url);
ASCIIEncoding encoding = new ASCIIEncoding();
String postData = "data";
byte[] data = encoding.getByte(postData);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = data.Length;
Stream reqStream = webRequest.GetRequestStream();
reqStream.Write(data, 0, data.Length);
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
string responseStr = new StreamReader(response.GetResponseStream()).ReadToEnd();
ASCIIEncoding encoding = new ASCIIEncoding();
String postData = "data";
byte[] data = encoding.getByte(postData);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = data.Length;
Stream reqStream = webRequest.GetRequestStream();
reqStream.Write(data, 0, data.Length);
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
string responseStr = new StreamReader(response.GetResponseStream()).ReadToEnd();
2013年1月30日 星期三
系統Memo - Silverlight Player影片起始載入問題
為了這個DRM專案被Silverlight搞了好久,菊花都痛了。
自行開發的Silverlight player一直有個問題,就是載入影片"有時候"會卡住,player狀態就停在manifest_ready和media_open中間不上不下。其實困擾有一大半都來自這個"有時候"出現的錯誤,說一是一說二是二程式有錯就不給跑簡單多了,所以我們花了滿多時間在釐清這個問題的原因。
最後從wireshark抓封包以及IIS server log發現,卡住的時候,player不會再送出任何request去抓video / audio fragment,大約是在第六秒和第八秒,切換抓取不同bitrate的時候就出了問題。
What the....!!!!!! How the hell would this happen
所以在載入影片的時候不能切換bitrate? Fuck!!! 這沒有道理啊!!! (後來發現切換bitrate真的跟卡住無關,因為測試用的silverlight player載入影片的時候切bitrate一點他媽的問題也沒有!!)
呼,真是太氣憤了。
我花了一下午新轉了一部低bitrate的影片,讓它容易切換,然後在測試player上卻捅出另一個樓子= = 太過頻繁的切換似乎會讓認證的cookie塞不進去(這只是猜測,實際讓認證抓不到cookie的原因不明),然後我又針對認證裡cookie null的處理作修改之後回來正式環境測試,一試就中,卡住的瞬間有夠想屎!!
所以下午他媽的白忙,player卡住不送request跟cookie null而被認證踢掉根本是兩個問題。
而且照這個情況看來,不送request對silverlight player或是IIS認證來說都不算是個錯誤,單純只是類似thread卡住而便秘又不敢講而已。
既然測試player沒問題,那就把正式player的流程改成跟它一樣吧!
所以我們把正式player的AutoPlay改成true,然後就跟喝了通樂一樣一路順暢............
What the F!!!!!!!!!!
至於為什麼會這樣到現在還沒搞懂。
另外,在載入影片的時候,如果預先載入的30秒都是同一個bitrate(ex. 1200k),什麼問題都沒有,所有的request也都會順利出現在wireshark以及server log裡;但只要載入的時候去抓另一個bitrate的fragment(ex. 2000k),就只會出現抓那個bitrate的request,也就是說,如果第六秒去抓,那就只看到第六秒的request(有時候會有第八秒的)。
為什麼其他的request都消失了,原因一樣不曉得,說不定跟cache有關係?
Update:
(冷靜)
1. 消失的request的確跟cache有關。
2. AutoPlay改成true之後,在第八秒卡住的問題依然存在,雖然無法確定跟AutoPlay無關,但至少不是唯一的原因。又做了一些測試後,我們猜測或許跟解析度有關,因為嵌在網頁上的player大小是400x300(4:3),所以在載入同樣是4:3的1200K影片(640x480)時一切正常,直到bitrate切換16:9的2000K影片(960x540),就立刻爆炸。這也是為什麼一開始在測試player沒有出現過這問題的原因,測試player一直是全螢幕打滿的,不會有比例不符合的錯誤。
但是網頁上的player牽涉到版面設計,沒辦法為了技術問題改變大小,所以我們改成在一開始載入的階段(manifest_ready -> media_opened)限制player抓取影片的bitrate,載入完成後才恢復成原先的multi-bitrate。
問題總算是解決了。
自行開發的Silverlight player一直有個問題,就是載入影片"有時候"會卡住,player狀態就停在manifest_ready和media_open中間不上不下。其實困擾有一大半都來自這個"有時候"出現的錯誤,說一是一說二是二程式有錯就不給跑簡單多了,所以我們花了滿多時間在釐清這個問題的原因。
最後從wireshark抓封包以及IIS server log發現,卡住的時候,player不會再送出任何request去抓video / audio fragment,大約是在第六秒和第八秒,切換抓取不同bitrate的時候就出了問題。
What the....!!!!!! How the hell would this happen
所以在載入影片的時候不能切換bitrate? Fuck!!! 這沒有道理啊!!! (後來發現切換bitrate真的跟卡住無關,因為測試用的silverlight player載入影片的時候切bitrate一點他媽的問題也沒有!!)
呼,真是太氣憤了。
我花了一下午新轉了一部低bitrate的影片,讓它容易切換,然後在測試player上卻捅出另一個樓子= = 太過頻繁的切換似乎會讓認證的cookie塞不進去(這只是猜測,實際讓認證抓不到cookie的原因不明),然後我又針對認證裡cookie null的處理作修改之後回來正式環境測試,一試就中,卡住的瞬間有夠想屎!!
所以下午他媽的白忙,player卡住不送request跟cookie null而被認證踢掉根本是兩個問題。
而且照這個情況看來,不送request對silverlight player或是IIS認證來說都不算是個錯誤,單純只是類似thread卡住而便秘又不敢講而已。
既然測試player沒問題,那就把正式player的流程改成跟它一樣吧!
所以我們把正式player的AutoPlay改成true,然後就跟喝了通樂一樣一路順暢............
What the F!!!!!!!!!!
至於為什麼會這樣到現在還沒搞懂。
另外,在載入影片的時候,如果預先載入的30秒都是同一個bitrate(ex. 1200k),什麼問題都沒有,所有的request也都會順利出現在wireshark以及server log裡;但只要載入的時候去抓另一個bitrate的fragment(ex. 2000k),就只會出現抓那個bitrate的request,也就是說,如果第六秒去抓,那就只看到第六秒的request(有時候會有第八秒的)。
為什麼其他的request都消失了,原因一樣不曉得,說不定跟cache有關係?
Update:
(冷靜)
1. 消失的request的確跟cache有關。
2. AutoPlay改成true之後,在第八秒卡住的問題依然存在,雖然無法確定跟AutoPlay無關,但至少不是唯一的原因。又做了一些測試後,我們猜測或許跟解析度有關,因為嵌在網頁上的player大小是400x300(4:3),所以在載入同樣是4:3的1200K影片(640x480)時一切正常,直到bitrate切換16:9的2000K影片(960x540),就立刻爆炸。這也是為什麼一開始在測試player沒有出現過這問題的原因,測試player一直是全螢幕打滿的,不會有比例不符合的錯誤。
但是網頁上的player牽涉到版面設計,沒辦法為了技術問題改變大小,所以我們改成在一開始載入的階段(manifest_ready -> media_opened)限制player抓取影片的bitrate,載入完成後才恢復成原先的multi-bitrate。
問題總算是解決了。
2013年1月11日 星期五
系統Memo - IIS Root Module 設定
指掛在Default Web Site層級的Module,掛載方式如一般應用程式(application)層級,
將DLL檔放在bin資料夾裡,讓web.config去讀取即可。
要注意的是,在這個層級的module,會影響底下所有應用程式的module,
必須額外加上不讓底下應用程式繼承本身設定的宣告,如下:
web.config內容:
< ?xml version="1.0" encoding="UTF-8"? >
< configuration >
< system.web >
< customErrors mode="Off"/ >
< /system.web >
< location path="." inheritInChildApplications="false" >
< system.webServer >
< modules >
< add name="DomainRedirect" type="DomainRedirect.Redirect"/ >
< /modules >
< /system.webServer >
< /location >
< /configuration >
將DLL檔放在bin資料夾裡,讓web.config去讀取即可。
要注意的是,在這個層級的module,會影響底下所有應用程式的module,
必須額外加上不讓底下應用程式繼承本身設定的宣告,如下:
web.config內容:
< ?xml version="1.0" encoding="UTF-8"? >
< configuration >
< system.web >
< customErrors mode="Off"/ >
< /system.web >
< location path="." inheritInChildApplications="false" >
< system.webServer >
< modules >
< add name="DomainRedirect" type="DomainRedirect.Redirect"/ >
< /modules >
< /system.webServer >
< /location >
< /configuration >
2013年1月1日 星期二
系統Memo - Cookie的使用
串流服務的http request分兩種,一種是manifest request,一種是chunk request;(manifest request: http://myserver.com/videopath/sample.ism/manifest?queryString,chunk request: /videopath/sample.ism?QualityLevels(128000)&Fragments(audio=460683900))
queryString只有在manifest request裡才會出現,也無法用程式加在接下來的chunk request上,所以為了辨別連線是屬於哪一個使用者,想到的最好解法就是使用cookie。
cookie的限制有以下幾點:
1. 無法即時改變cookie的值:cookie儲存在client端,在server端建立並設定值之後,由response帶過去client,下一次的request才會抓的到cookie;要改變其中的值或是刪除它,都必須由response通知client端,也就是cookie的變更一定存在request和response的時間差。
2. 瀏覽器的安全設定不相同:由於服務是由兩台不同domain的server提供,認證程式發給的cookie屬於第三方,這方面Chrome比較開放,並不禁止任何第三方cookie寫入,對認證沒有什麼影響;IE有限制第三方cookie,必須在cookie header中加入P3P設定 - HttpContext.Current.Response.AddHeader("P3P", "CP=\"CAO PSA OUR\""); Safari一樣有限制第三方cookie,且對於Domain的認定並不是看cookie內的設定來決定,而是直接看來源,這就很麻煩了,代表為了Safari一種瀏覽器,我必須將兩種服務放在同一個domain下。
3. 相同的request url不會更新cookie:也就是說,如果我要把cookie的值當作session用,我必須確定不同session的request url不會一樣,所攜帶的cookie值才會不一樣;經測試,相同的url無視於response的更新指令,而被瀏覽器視作cookie無須更新。
4. cookie允許設定string以外的值,但是request只取的到string的值
總而言之,cookie並不好用,
如果能夠像Wowza那樣將sessionid加在url上就不用被cookie搞了。
2012年10月17日 星期三
系統Memo - IHttpModule 中使用Session State
這個問題其實挺弔詭的,沒有什麼文件清楚的寫出來(該死的微軟)
要在IHttpModule中使用Session有非常多的限制:
1. 網路上眾說紛紜,有人說只在AcquireRequestState和PreRequestHandlerExecute兩個事件中,才有辦法使用Session,但也有人說http module根本沒辦法使用session,造成不少困擾。
2. 經測試,即使是在上述兩個事件中,HttpApplication.Context.Session依然為null,我的猜測是這樣的方法只適用於.aspx之類的http request,其餘一律行不通。(我發的http request是抓.png或是manifest這類的行為)
最後採用的解法是:
http://forums.asp.net/t/1098574.aspx/1
我看不太懂裡面針對handler物件繞來繞去的原因是什麼,只大概猜說是要自己宣告一個Handler類別,產生handler物件,然後用原本的Application.Context.Handler傳進來,藉此啟動SessionStateModule,讓SessionState成為avaliable狀態。
以下只擷取相關部分,RequestBegin之類的事件省略,
Code snippet:
public void Init(HttpApplication application)
{
// following two event handler are both required
application.PostAcquireRequestState += new EventHandler(OnPostAcquireRequestState);
application.PostMapRequestHandler += new EventHandler(OnPostMapRequestHandler);
}
/**
* for the usage of SessionState, replace the original handler with ours, force SessionState to be valiable
**/
public void OnPostMapRequestHandler(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (application.Context.Handler is IReadOnlySessionState || application.Context.Handler is IRequiresSessionState)
{
// no need to replace the original handler
return;
}
// swap the original handler
application.Context.Handler = new TempHandler(application.Context.Handler);
}
public void OnPostAcquireRequestState(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TempHandler handler = HttpContext.Current.Handler as TempHandler;
if (handler != null)
{
HttpContext.Current.Handler = handler.myHandler;
}
// from this moment, SessionState is valiable
HttpSessionState session = application.Context.Session;
}
/**
* A temp handler used to force the SessionStateModule to load session state
**/
public class TempHandler : IHttpHandler, IRequiresSessionState
{
internal readonly IHttpHandler myHandler; // store original application context handler
public TempHandler(IHttpHandler originalhttpHandler)
{
this.myHandler = originalhttpHandler;
}
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException("InvalidOperationException");
}
public bool IsReusable
{
get { return false; }
}
}
另外,module類別除了繼承IHttpModule以外,必須再繼承IRequiresSessionState。
Anyway,這個方法讓我成功取到Session.SessionID,原理之後再慢慢思考。
要在IHttpModule中使用Session有非常多的限制:
1. 網路上眾說紛紜,有人說只在AcquireRequestState和PreRequestHandlerExecute兩個事件中,才有辦法使用Session,但也有人說http module根本沒辦法使用session,造成不少困擾。
2. 經測試,即使是在上述兩個事件中,HttpApplication.Context.Session依然為null,我的猜測是這樣的方法只適用於.aspx之類的http request,其餘一律行不通。(我發的http request是抓.png或是manifest這類的行為)
最後採用的解法是:
http://forums.asp.net/t/1098574.aspx/1
我看不太懂裡面針對handler物件繞來繞去的原因是什麼,只大概猜說是要自己宣告一個Handler類別,產生handler物件,然後用原本的Application.Context.Handler傳進來,藉此啟動SessionStateModule,讓SessionState成為avaliable狀態。
以下只擷取相關部分,RequestBegin之類的事件省略,
Code snippet:
public void Init(HttpApplication application)
{
// following two event handler are both required
application.PostAcquireRequestState += new EventHandler(OnPostAcquireRequestState);
application.PostMapRequestHandler += new EventHandler(OnPostMapRequestHandler);
}
/**
* for the usage of SessionState, replace the original handler with ours, force SessionState to be valiable
**/
public void OnPostMapRequestHandler(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (application.Context.Handler is IReadOnlySessionState || application.Context.Handler is IRequiresSessionState)
{
// no need to replace the original handler
return;
}
// swap the original handler
application.Context.Handler = new TempHandler(application.Context.Handler);
}
public void OnPostAcquireRequestState(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TempHandler handler = HttpContext.Current.Handler as TempHandler;
if (handler != null)
{
HttpContext.Current.Handler = handler.myHandler;
}
// from this moment, SessionState is valiable
HttpSessionState session = application.Context.Session;
}
/**
* A temp handler used to force the SessionStateModule to load session state
**/
public class TempHandler : IHttpHandler, IRequiresSessionState
{
internal readonly IHttpHandler myHandler; // store original application context handler
public TempHandler(IHttpHandler originalhttpHandler)
{
this.myHandler = originalhttpHandler;
}
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException("InvalidOperationException");
}
public bool IsReusable
{
get { return false; }
}
}
另外,module類別除了繼承IHttpModule以外,必須再繼承IRequiresSessionState。
Anyway,這個方法讓我成功取到Session.SessionID,原理之後再慢慢思考。
2012年10月16日 星期二
系統Memo - IIS Server網站掛載HTTP Module
1. 將C#程式編譯成.dll檔,放置在網站目錄下bin資料夾,與web.config層級相同。
2. web.config設定方式如下:
< configuration >
< system.web >
< customErrors mode="Off" />
< /system.web >
< system.webServer >
< modules >
< add type="NameSpace.ModuleName" name="NameSpace" />
< /modules >
< /system.webServer >
< /configuration >
3. 採用介面為IHttpModules。
2. web.config設定方式如下:
< configuration >
< system.web >
< customErrors mode="Off" />
< /system.web >
< system.webServer >
< modules >
< add type="NameSpace.ModuleName" name="NameSpace" />
< /modules >
< /system.webServer >
< /configuration >
3. 採用介面為IHttpModules。
訂閱:
文章 (Atom)