2011-10-03

以 Java 實作 Base 64 Encoder

或許有人會覺得奇怪,Java 本身已經有支援 Base 64 Encoder 了,為什麼還要自己重新寫一個? 事實上,Java 平台的 Base64Encoder 需要 import sun.misc.BASE64Encoder,然而這個類別卻不是在所有平台上面都可以正常執行(我個人的經驗是,在 android 執行時會當機)。 以下為 Base 64 Encoder 實作程式碼,歡迎各位朋友切磋學習。
private static String base64_encode( byte[] bytes ) {
        String[] base64 = { "A", "B", "C", "D", "E", "F", "G", "H",
                            "I", "J", "K", "L", "M", "N", "O", "P",
                            "Q", "R", "S", "T", "U", "V", "W", "X",
                            "Y", "Z", "a", "b", "c", "d", "e", "f",
                            "g", "h", "i", "j", "k", "l", "m", "n",
                            "o", "p", "q", "r", "s", "t", "u", "v",
                            "w", "x", "y", "z", "0", "1", "2", "3",
                            "4", "5", "6", "7", "8", "9", "+", "/" };
        String encoded = "";

        int pad_length = 0;
        if ( bytes.length % 3 == 1 )
            pad_length = 2;
        else if ( bytes.length % 3 == 2 )
            pad_length = 1;
        
        byte[] padded = new byte[ bytes.length + pad_length ];

        for( int i = 0; i < bytes.length; ++i ) {
            padded[ i ] = bytes[ i ];
        }
        if ( pad_length == 1 ) {
            padded[ padded.length - 1 ] = 0;
        } else if ( pad_length == 2 ) {
            padded[ padded.length - 1 ] = 0;
            padded[ padded.length - 2 ] = 0;
        }
        
        for( int i = 0; i < padded.length; i += 3 ) {
            encoded += base64[ ( ( padded[ i ] & 255 ) >>> 2 ) ];
            encoded += base64[ ( ( ( padded[ i ] & 3 ) << 4 ) | ( ( padded[ i + 1 ] & 255 ) >>> 4 )  ) ];
            encoded += base64[ ( ( ( padded[ i + 1 ] & 15 ) << 2 ) | ( ( padded[ i + 2 ] & 255 ) >>> 6 )  ) ];
            encoded += base64[ ( padded[ i + 2 ] & 63 ) ];
        }
        
        encoded = encoded.substring( 0, encoded.length() - pad_length );
        
        if ( pad_length == 1 ) {
            encoded += "=";
        } else if ( pad_length == 2 ) {
            encoded += "==";
        }

        return encoded;
    }

2011-09-02

再玩一下 AES 加密解密

上次在這篇「玩了一下AES加密解密」裡面寫的程式碼有些缺點,就是加密過後的結果是 byte[] 而不是 String,對於 Java 的操作上不是很方便。看了幾位高手的博文,自己做了些改良,同時也將程式碼放上來拋磚引玉。主要的改良是透過 BASE64Encoder 和 BASE64Decoder 將 byte[] 轉為可讀的英文字母 + 數字字串,這在網址的傳遞上也有好處,不需要變成%xx%xx的 UTF-8 形式,更容易偵錯與閱讀,也不減少其安全性。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder; 

public class Base64AES {

    public static String decrypt( String key, String text ) throws Exception {
        byte [] results = decrypt( key.getBytes(), new BASE64Decoder().decodeBuffer( text ) );
        return new String( results );
    }

    public static String encrypt( String key, String text ) throws Exception {
        byte[] results = encrypt( key.getBytes(), text.getBytes() );
        return new BASE64Encoder().encode( results );
    } 
    
    public static byte[] encrypt( byte[] key, byte[] msg ) throws Exception {
        if ( key.length != 16 ) {
            throw new IllegalArgumentException( "Key length should be 16." );
        }
        SecretKeySpec spec = new SecretKeySpec( key, "AES" );
        IvParameterSpec ivSpec = new IvParameterSpec( key );
        Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
        cipher.init( Cipher.ENCRYPT_MODE, spec, ivSpec );
        return cipher.doFinal( msg );
    }
    
    public static byte[] decrypt( byte[] key, byte[] msg ) throws Exception {
        if ( key.length != 16 ) {
            throw new IllegalArgumentException( "Key length should be 16." );
        }
        SecretKeySpec spec = new SecretKeySpec( key, "AES" );
        Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
        IvParameterSpec ivSpec = new IvParameterSpec( key );
        cipher.init( Cipher.DECRYPT_MODE, spec, ivSpec );
        return cipher.doFinal( msg );
    }
    
    public static void main( String[] args ) throws Exception {
        String msg = "This is so easy.";
        
        System.out.println( "原字串: " + msg );
        System.out.println( "加密後: " + encrypt( "vegafish12345678" , msg ) );
        System.out.println( "解密後: " + decrypt( "vegafish12345678", encrypt( "vegafish12345678" , msg ) ) );
    }

}
執行結果如下:
原字串: This is so easy.
加密後: KczRl5uSsrgfwWRKpfR5FoKEIVU0jPvxX1VsEYl/jl0=
解密後: This is so easy.

2011-08-31

少子化的感想

少子化對臺灣所造成的影響,就是未來20年的經濟不景氣甚至倒退、生產力被侵蝕、到消亡的地步,已經有很多書籍探討,如《人口減少經濟時代》(ISBN 978-986-788942-3),在此就不多做論述了。

政府為何要人民生育?因為我們追求的是經濟成長率,我們一輩子都活在成長的年代,不管是營業額、GDP。一兩季的營業額負成長,即使是大如台積電的公司,員工、股東們會怎麼看?同樣的,當經濟負成長時,政府就得要擴大公共支出、舉債建設,以便提振景氣。


2011-08-24

玩了一下AES加密解密

我將自己寫的程式碼貼上來,這是很簡短的程式,希望高手能稍加提點我自己不足之處。
import javax.crypto.Cipher;

import javax.crypto.spec.SecretKeySpec;


2011-08-16

Re: [新聞] 台灣生育率跌破1全球最低 (by hedonic.bbs@ptt.cc)

作者: hedonic (黑東尼克) 看板: Gossiping
標題: Re: [新聞] 台灣生育率跌破1全球最低
時間: Mon Aug 15 15:12:29 2011


2011-08-13

富爸爸窮爸爸 之 現金流遊戲 (Cashflow 202 e-game) 介紹

現金流遊戲這個遊戲已經有十幾年的歷史,其目的是將投資理論(Modern Portfolio Theory)教育給普羅大眾。這個遊戲是由「富爸爸.窮爸爸」系列書籍作者「羅伯特.清崎」所開發,一開始是紙上遊戲,後來演變為電子遊戲的形式。以「寓教於樂」的方式,讓使用者了解近代現實生活之投資理論,有很重要的幫助。

「富爸爸.窮爸爸」系列書籍旨要在提倡一個重要的觀念(轉載自 Wikipedia):「資產就是將錢放進你口袋裡的東西,而負債則是把你口袋的錢拿走的東西。」資產和負債不同的現金流向,會造成不同的財富結果。窮人只通過工作獲取收入,通過消費將掙來錢花出去,沒有任何資產。中產階級通過工作獲取收入,再去購買一些他們認為是資產的負債,然後通過償還負債,花光他們的錢,他們同樣也沒有資產。而富人則通過購買資產來產生收入,再用收入來購買資產,不斷地循環下去,最終獲得大量的財富,實現無需工作也能不斷獲得收入的財務自由狀態。同時,他認為,能真正讓人達到財務自由的,不是工作,也不是金錢,而是能帶來源源不斷現金流的資產


2011-08-01

中油直營站地圖

此系列地圖中,標示了臺灣中油公司直營加油站的地點與地址,並做以下標示:
黃色:提供刷卡自助加油服務的加油站
綠色:24小時營業的加油站
紅色:提供刷卡自助加油服務,並且24小時營業的加油站

2011-07-31

如何用 Blendtec 製作芒果奇異果飲料

先讓我們看看這位大叔如何用 Blendtec 把 iPhone4 打成碎片好了。(默)




2011-05-04

使用 RMaps 記錄路徑並匯出到 Google Maps

RMaps 是 android 的地圖應用程式,一般用在手機無網路連線時,來觀看離線地圖。如何下載並製作離線地圖在 Dr. TYT 的 Android 地圖 有教學,這裡就不贅述了。

但其實很少人知道,RMaps 有如同另一個應用程式 My Tracks 的功能,可以記錄手機移動的路徑,並且可以匯出到 Google maps 做記錄。以下為使用此功能的步驟詳解: