2015年10月29日 星期四

IOS 實機測試-上集

    因為CODOVA專案是允許在AndroidIOS的專案,於是作者決定把IOS部署的過程經驗寫下來,果然… 蘋果不是好吃的…  中間的過程好複雜喔,所以寫了簡單雜記,順便把一些好心人留下來的記錄作個簡單的整理,方便日後查找。

1.    申請下戴開發者憑證
l   請至application.com 註冊開發APPLE ID


登入後點選 Programs & Add-one 購買APP Developer



l 購買後 Membership 出現 到期日期,如果允許Automatic Renewal 將會每年自動購買APP Developer à 各位請謹慎小心















l  重新登入後多了以下幾個功能,點選Certificates Identifiers & Profiles












l   在點選IOS Apps Certificates














l      在點選右上角+符號
















l   畫面移至最下方,點選網址worldwide Developer Relations Certificate Authority


















l   下戴憑證檔案





l   當開啟鑰匙金鑰後,選擇Apple Worldwide Developer Relations Certification Authority














l   開啟鑰匙圈存取後à選擇憑證輔助程式à從憑證授權要求憑證














l   將憑證儲存到指定磁碟













l   可以儲存在任何地方,只要你記得的位置








l   出現密碼要求登入…  如果登入MAC有密碼限制,你就輸入登入的密碼








2.  IOS裝置與開發者憑證的相關設定

l   請至application.com作登入後














l   點選 +
















l   請點選IOS App Development è繼續

l   出現要求上傳憑證的上傳檔案,請將您先前下戴的憑證檔上傳à按下Generate

PS: 此階段原作者說要等待管理員認可後,才可下戴,但我上傳檔案後,就立刻可以下戴憑證了,不知道是不是開發者帳號登入的關係。

l   終於產生新的憑證按下Download 就可以下戴憑證
l   下戴項目中就出現ios_development.cerè 對此檔案點擊兩下,自動寫入MAC機器設備中
l   點選Devicesè 發佈至實體機,需要把手機的唯一碼UUID登入在IOS Devices

接著開啟Xcode / Window / Organizer,在Identifier會看到一串數字,此數字為iPhone識別碼,將它拷貝下來。
PS: 最多只允許發佈100隻手機註冊,而且不允許刪除的…


 l   點選APP IDS è 新增 + 
 l   新增APP ID
App ID Description 可以寫簡單的敘述
Bundle Identifier中,都會用網域名稱+程式名稱
l   新增APP ID 之後
PS: 如果想要推播功能另外開啟此功能… 還要下戴憑證… 等等… 不過已經不在此次討論範圍中

3.  匯入XCODE的憑證
l   點選Provisioning Profilesè 點選
l   點選IOS APP Development à 點選Continue


l   選擇APP IDà選擇剛剛新增的App ID
l   勾選IOS開發者,如果有多位開發者,可以複選
l   勾選IOS的手持裝置後à按繼續 
 l   輸入Profile Name à Generate 應該就大功告成

l   狀態為『綠色』燈

接下來將下戴的憑證匯到XCODE就完成第一階段啦~~~~~  待續


參考文獻


















2015年9月17日 星期四

如何在C# 和JavaScript 用AES 加解密

    作者使用WebAPI(C#)來傳遞資料,但擔心個資法等議題,特別針對個人隱私的資料加密,以免資料在網站上暴露,其中加密的工具,網站上也有不少,其中c# 我就使用.net framework 4.5 提供System.Security.Cryptography 來加密WebAPI的資料,再由JavaScript ( aes.js) 負責將資料解密回來,這樣就能保護個人穩私的資料,以下是示範教學。

一、 C# 的加密/解密函式

public class AESEncrytDecry
    {
//解密資料
        public static string DecryptStringAES(string cipherText)
        {
            var keybytes = Encoding.UTF8.GetBytes("8080808080808080");   //自行設定,但要與JavaScript 一致
            var iv = Encoding.UTF8.GetBytes("8080808080808080"); // 自行設定,但要與JavaScript 一致
            var encrypted = Convert.FromBase64String(cipherText);
            var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
            return string.Format(decriptedFromJavascript);
        }

        private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv)
        {
           if (cipherText == null || cipherText.Length <= 0)
            {
                throw new ArgumentNullException("cipherText");
            }
            if (key == null || key.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }
            if (iv == null || iv.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }          
            string plaintext = null;
            using (var rijAlg = new RijndaelManaged())
            {
                rijAlg.Mode = CipherMode.CBC;
                rijAlg.Padding = PaddingMode.PKCS7;
                rijAlg.FeedbackSize = 128;
                rijAlg.Key = key;
                rijAlg.IV = iv;
                var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                try
                {
                    using (var msDecrypt = new MemoryStream(cipherText))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {                               
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
                catch
                {
                    plaintext = "keyError";
                }
            }
            return plaintext;
        }
       //加密資料
        public static string EncryptStringAES(string cipherText)
        {
            var keybytes = Encoding.UTF8.GetBytes("8080808080808080");   //自行設定
            var iv = Encoding.UTF8.GetBytes("8080808080808080");         //自行設定
            var EncryptString = EncryptStringToBytes(cipherText, keybytes, iv);
            return Convert.ToBase64String(EncryptString);
        }
        private static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
        {         
            if (plainText == null || plainText.Length <= 0)
            {
                throw new ArgumentNullException("plainText");
            }
            if (key == null || key.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }
            if (iv == null || iv.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }
            byte[] encrypted;
            using (var rijAlg = new RijndaelManaged())
            {
                rijAlg.Mode = CipherMode.CBC;
                rijAlg.Padding = PaddingMode.PKCS7;
                rijAlg.FeedbackSize = 128;
                rijAlg.Key = key;
                rijAlg.IV = iv;
                var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                using (var msEncrypt = new MemoryStream())
                {
                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            return encrypted;
        }
    }

   
範例程式片段:透過實體層的函式,已將部份回傳值加密

foreach (DataRow dr in dt.Rows)
{
    viewPatientObj.sickNo =  AESEncrytDecry.EncryptStringAES(dr["病歷編號"].ToString()); 
    viewPatientObj.name = dr["病患姓名"].ToString(); 
    viewPatientObj.sex = dr["性別"].ToString();
    viewPatientObj.birthDay = AESEncrytDecry.EncryptStringAES(dr["出生日期"].ToString());
    viewPatientObj.mobile = AESEncrytDecry.EncryptStringAES(dr["行動電話"].ToString());
    viewPatientObj.tel = AESEncrytDecry.EncryptStringAES(dr["住宅電話"].ToString());
    viewPatientObj.address = AESEncrytDecry.EncryptStringAES(dr["地址"].ToString());
}


Web API:
        [EnableCors(
          origins: "*",
          headers: "accept,content-type,origin",
          methods: "get,post"), HttpGet]
        [Route("api/values/readPatient/{sickNo}/{pregistDate}")]
        public viewPatient readPatient(string sickNo,string pregistDate)
        {
            return controlClinicObj.readPatient(sickNo, pregistDate);
        }
l   加密:   AESEncrytDecry.EncryptStringAES(文字);
l   解密:   AESEncrytDecry. DecryptStringAES (文字);

二、 JavaScript 的加密/解密函式


<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="scripts/aesEncrytDecry.js"></script>


檔名aesEncrytDecry.js

<script>
var key = CryptoJS.enc.Utf8.parse('8080808080808080');  //需要和伺服器端一致,否則… 無法解密
var iv = CryptoJS.enc.Utf8.parse('8080808080808080');   //需要和伺服器端一致,否則… 無法解密
var aesEncryDecry = {
    decryptStringAES: function (strEncryptText) {
        var decrypted = CryptoJS.AES.decrypt(strEncryptText, key, {
            keySize: 128 / 8,
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return decrypted.toString(CryptoJS.enc.Utf8);
    },
    encryptStringAES: function (strOrignText) {
        var encrypted = CryptoJS.AES.encrypt(strOrignText, key,{
            keySize: 128 / 8,
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.toString();
    }
};
</script>

Javascript 的範例程式: 解密
  
$.ajax({
        url: 'http://' + clinicIP + '/webClinic/api/values/readPatient/' + sickNo + "/" + date,
        type: 'GET',
        error: function (error)
        {
            alert(error)
        },
        success: function (data) {
            $('#patientPage_name').html(data.name + "(" + data.sex + ")");
            var birthday = "";
            if (data.birthDay != null) {
                var decodeBirthDay =aesEncryDecry.decryptStringAES(data.birthDay);
                if (decodeBirthDay.trim() != "") {
                    birthday = decodeBirthDay.substring(0, 3) + "-" + decodeBirthDay.substring(3, 5) + "-" + decodeBirthDay.substring(5, 7);
                }
            }           
            $('#patientPage_birthday').html(birthday);
            $('#patientPage_addr').html(aesEncryDecry.decryptStringAES(data.address));
            $('#patientPage_tel').val(aesEncryDecry.decryptStringAES(data.tel));
            $('#patientPage_mobile').val(aesEncryDecry.decryptStringAES(data.mobile));

            //解密約診資料,如果空值就填空白
            var pregistContext = "";
            if (data.pregistContext != null) {
                pregistContext = aesEncryDecry.decryptStringAES(data.pregistContext);
            }

            $('#patientPage_pregistContext').val(pregistContext);
        }
    });



l   加密:aesEncryDecry. encryptStringAES (文字)
l   解密:aesEncryDecry.decryptStringAES(文字)

三、 示範結果

傳送資料是經過加密
  
Codova APP JS解譯後,回復原始的資料





















    對於AES這方面有困擾的朋友們,不知道是否有幫助到各位,感謝各位耐心的看完本篇文章,未來也能繼續期許能寫出好文章,讓網路的資源更豐富。

參考文獻: