作者使用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這方面有困擾的朋友們,不知道是否有幫助到各位,感謝各位耐心的看完本篇文章,未來也能繼續期許能寫出好文章,讓網路的資源更豐富。
參考文獻:
非常好的分享,解決了我卡住的問題點非常感謝。
回覆刪除謝謝你喜歡我的文章
回覆刪除