הפעם נדבר על הצפנה אסימטרית. מה הכוונה? ובכן, החיסרון הכי גדול של הצפנה סימטרית הוא כיצד להעביר לצד השני את המפתח/סיסמא. הרי הסיבה העיקרית שרצינו להשתמש בהצפנה היא כי אנחנו לא בוטחים בדרך שהמידע עובר בה ובאנשים שיראו אותו בדרך, אז איך נעביר את המפתח באותו הדרך??אז יש פיתרון... הצפנה אסימטרית. הפעם אין מפתח אחד שיכול גם להצפין וגם לפתוח את ההצפנה, אלא יש מפתח אחד (מפתח פרטי) שיכול גם להצפין וגם לפענח את ההצפנה, ויש מפתח אחד (מפתח ציבורי) שיכול רק להצפין. אז מה יצא לנו מזה? ככה, אנחנו מפרסמים לכולם את המפתח הציבורי שלנו, אז הם יכולים כעת להצפין את המידע מאצלהם, ואז לשלוח אלינו, ורק אנחנו עם המפתח הפרטי יכולים לפענח את ההצפנה... נחמד...ואם אני רוצה לשלוח להם תשובה מוצפנת בחזרה? אז שוב, או שהצד השני ישלח לי מפתח ציבורי משלו, ואז לאחר שאצפין את התשובה עם המפתח שלו, אחזיר לו את המידע המוצפן והוא יפענח אותו עם המפתח הפרטי שלו, או, שבעזרת המפתח הציבורי ששלחתי לצד השני בהתחלה, הוא יצפין לי מפתח/סיסמא להצפנה סימטרית ואז פשוט נמשיך את השיחה שלנו בעזרת הצפנה סימטרית(שזו השיטה הסטנדרטית שבה עובד SSL) . למה שיטה זו עדיפה? ובכן, ההצפנה האסימטרית דורשת הרבה מאמץ מהמעבד והיא מאוד איטית ביחד לשיטה הסימטרית.ועכשיו לקצת קוד:
קודם ניצור זוג מפתחות , אם עדיין אין לנו:המחלקה ב C# שמשמשת להצפנה אסימטרית נקראת RSACryptoServiceProvider (שלוש אותיות ראשונות על שם בוני האלגוריתם...)
ניצור אובייקט חדש, והוא כבר ייצר עבורנו זוג מפתחות:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider ();
את המפתח הפרטי (שלנו, שיכול לגם לפענח וגם להצפין) ניצור באמצעות הפונקציה ToXmlString עם פרמטר true להוספת המידע של מפתח פרטי בסטרינג שמתקבל:
string privateKey= rsa.ToXmlString(true);
את המפתח הציבורי ניצור באותה שיטה אך על ידי שליחת ערך false כדי שלא להוסיף את המידע על מפתח פרטי לה
string publicKey = rsa.ToXmlString(false);
כעת נפרסם את המפתח הציבורי שלנו, ומי שירצה להצפין לנו הודעה ישתמש בו בעת ההצפנה:
ניצור אובייקט הצפנה:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider ();
נאתחל אותו עם המפתח הציבורי:
rsa.FromXmlString(publicKey);
נהפוך את המידע שאנו רוצים להצפין למערך בתים:
byte[] clearData=Encoding.UTF8.GetBytes(clearText);
נבצע את ההצפנה :
byte[] encryptedData = rsa.Encrypt(clearData, false);
ונהפוך חזרה לסטרינג שניתן לשליחה בתור טקסט באימייל או דף אינטרנט:
string encryptedString = Convert.ToBase64String(encryptedData);
כעת לאחר שהצד השני שלח לנו את הסטרינג המוצפן, נשתמש במפתח הפרטי לפענח את ההודעה :
ניצור אובייקט הצפנה חדש ונאתחל אותו עם המפתח הפרטי שלנו:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider ();
rsa.FromXmlString(privateKey);
נהפוך את המידע המוצפן שקיבלנו למערך בתים:
byte[] encryptedData = Convert.FromBase64String(encryptedString);
נבצע את הפיענוח:
byte[] clearData = rsa.Decrypt(encryptedData, false);
ונהפוך לטקסט קריא:
string clearText = Encoding.UTF8.GetString(clearData);
זהו... די פשוט
להורדת קבצי מקור ופרוייקט
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
אני אכתוב כמה מילים על שירותי ווב מאובטחים. כשאני בונה WebService ואני רוצה שהמשתמשים יזדהו לפני השימוש, אז נכון שאני יכול לדרוש שחלק מהפרמטרים יהיו השם משתמש וסיסמה, אבל זו לא הדרך הטובה יותר, דרך יותר נכונה תהיה להשתמש ב Header שהסרביס מקבל, והוא יכיל את שם המשתמש והסיסמה.
בואו ניצור משהו פשוט:
עכשיו ניצור מחלקה חדשה שתייצג את ה Header שלנו
public class SecurityHeader : System.Web.Services.Protocols.SoapHeader
{
public string username;
public string pass;
}
כעת נגיד לשירות שלנו שהוא אמור לחכות ל Header הזה
[WebMethod]
[SoapHeader("SecurityHeader")]
public string HelloWorldSecure() {
כפי שניתן לראות מדובר בסך הכל בתוספת של שורה אחת
עכשיו עוד דבר קטן, נגדיר משתנה גלובלי מסוג המחלקה של ה Header שלנו
public class SayHello : System.Web.Services.WebService
{
public SecurityHeader secHeader;
כעת כל פעם שמישהו יקרה לסרביס שלנו, השרת יבדוק אם יש לו Header מהסוג שציינו, ואם כן הוא יכניס את הערכים שהוא קיבל למשתנה הגלובלי שלנו במחלקה. כעת בתוך השירות אנחנו רק צריכים לבדוק שאכן המשתנה הגלובלי קיבל ערך(אכן יש כזה Header) ואז ניתן לבדוק את הנתונים שלו (שם משתמש וסיסמה במקרה שלנו)
if (secHeader == null)
{
return "Please authenticate!";
}
if (secHeader.username == "tal" && secHeader.pass == "giladi")
{
return "Shalom " + secHeader.username;
}
else
{
return "Bad username or password";
}
עכשיו להשתמש בזה בצד הלקוח זה עוד יותר קל אפילו...
ניצור הפניה לשירות שלנו
קראתי להפניה הזאת server_sayHello
ניצור אובייקט של ההפניה הזאת
server_sayHello.SayHello sayHello = new server_sayHello.SayHello();
ניצור הפניה של ה Header שלנו באותה צורה
server_sayHello.SecurityHeader secHeader = new server_sayHello.SecurityHeader();
ניתן ערכים לשם והסיסמה
secHeader.UserName = "tal";
secHeader.Password = "giladi";
sayHello.SecurityHeaderValue = secHeader;
וזהו... פשוט נקרא לשירות:
string result = sayHello.HelloWorldSecure();
* אם אנחנו רוצים שהשירות יהיה מאובטח גם בעזרת SSL,(בהנחה שיש לכם תעודה והגדרתם אותה לשרת) פשוט נעשה מה שאנחנו עושים בדף ווב רגיל,
נוסיף שורה בסרביס עצמו, בתוך הפונקציה שלנו:
if (!HttpContext.Current.Request.IsSecureConnection)
{
return "Please use secure connection!";
}
להורדת הפרוייקט
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
חתימה דיגיטילית זה בעצם שילוב של מפתח ציבורי/פרטי עם האש. אני רוצה להשיג 2 מטרות בבת אחת- גם לוודא שהמכתב שהנמען קורא הוא המכתב שאני כתבתי והמידע בו לא השתנה, וגם שזהו אכן מכתב שאני כתבתי ולא מישהו אחר. כדי להשיג את המטרה הראשונה, אנחנו משתמשים בהאש – כך אנו מוודאים שהמידע במכתב לא השתנה, והמטרה השניה מושגת על ידי שימוש בהצפנה על ידי המפתח הפרטי שלי- אבל הצפנה רק של ערך ההאש, לא של המכתב כולו.
ועכשיו לקצת קוד:
using System.Security.Cryptography;
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
* ניתן באופן זהה במחלקה RSACryptoServiceProvider ושם ניתן גם לציין את האלגוריתם לביצוע ההאש.
המחלקה הזאת תבצע בעצם את פעולת ההאש והחתימה ביחד. אם כבר יש לי מפתח פרטי אזי נאתחל את המחלקה איתו:
dsa.FromXmlString(privatekey);
אם לא אז המחלקה תיצור באופן אוטומטי זוג מפתחות. זיכרו שאנחנו אמורים לספק לצד שמקבל את המידע את המפתח הציבורי שלנו כדי שיוכל לוודא איתו את החתימה, אז אם אין לי עדיין מפתח ציבורי נקבל עכשיו אחד חדש:
string publickey = dsa.ToXmlString(false);
זהו בעצם, עכשיו פשוט נייצר את החתימה:
byte[] signature = dsa.SignData(mydata);
וניתן להפוך לסטרינג כמובן:
string result = Convert.ToBase64String(signature);
עכשיו אנחנו מפרסמים את המידע שכתבנו, את המפתח הציבורי ואת החתימה. הצד השני יבצע את הפעולות הבאות כדי לוודא שהחתימה מתאימה:
1. ניצור אובייקט מהמחלקה המתאימה:
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
2. ניתן לו את המפתח הציבורי שקיבלנו:
dsa.FromXmlString(publickey);
3. וכעת ניתן לו את המידע עצמו ואת החתימה ונקבל ערך בוליאני האם החתימה מתאימה או לא:
bool match = dsa.VerifySignature(data, signature);
וזהו...
להורדת קבצי המקור והפרוייקט
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
בהצפנה סימטרית, הכוונה היא שניתן לבצע הצפנה של הטקסט(encryption) והפיכת הטקסט המוצפן לטקסט קריא שוב(decryption), בעזרת אותו מפתח. זאת אומרת שאם יש לי את הסיסמא(המפתח) אני יכול גם להצפין קוד וגם לקרוא אותו, להבדיל משיטות אחרות שבהם יש מפתח שיכול רק להצפין למשל (נראה בע"ה בפוסטים אחרים...)
טוב, אז איך זה הולך...
קודם נבחר שיטת הצפנה, דוט נט מציע מספר אלגוריתמים שמבצעים הצפנה סימטרית, אולם רק אחד מהם הוא בקוד מנוהל, ולכן נבחר אותו וניצור אובייקט חדש
using System.Security.Cryptography;
RijndaelManaged myAlg = new RijndaelManaged();
למרות שמפתח ההצפנה (סיסמא) אמור להיות סיסמא אחת, בפועל יש לנו 2 סיסמאות (הסיסמא השניה נקראת IV – וקטור האיתחול ובעצם מגבירה את רמת הבטיחות, אבל לשם הפשטות נתייחס אל שניהם כסיסמאות)
ניצור לנו 2 סיסמאות
String pass1=”mypassword1”;
String pass2=”mypassword2”;
כדי שאלגוריתם ההצפנה יוכל להשתמש בסיסמאות עלינו להפוך אותם למערך של בתים באורך קבוע של 32 ו 16 בתים בהתאמה. נהפוך את הסטרינגים למערך בתים ונשתמש בפונקציית עזר שתבצע את בדיקת האורך:
byte[] password1= Encoding.UTF8.GetBytes(pass1);
password1= SetArraySize(password1, 32);
byte[] password2= Encoding.UTF8.GetBytes(pass2);
password2= SetArraySize(password2, 16);
נהפוך המידע שברצונו להצפין למערך של בתים:
String clearText=”my credit card number”;
byte [] data= Encoding.UTF8.GetBytes(clearText);
כעת ניתן לאלגוריתם ההצפנה את הסיסמאות:
myAlg.Key = key;
myAlg.IV = IV;
כעת ניצור את האובייקט שישתמש באלגוריתם כדי להצפין את המידע :
ICryptoTransform encryptor = myAlg.CreateEncryptor();
ניצור אובייקט שיכיל את התוצאה של ההצפנה:
MemoryStream outstream = new MemoryStream ();
נגדיר לאובייקט ההצפנה לבצע הצפנה (ולא קריאה מטקסט מוצפן)
CryptoStream encryptStream = new CryptoStream (outstream, encryptor, CryptoStreamMode.Write);
ונבצע את ההצפנה:
encryptStream.Write(data, 0, data.Length);
encryptStream.Close();
והתוצאה התקבלה כמערך של בתים:
byte [] result= outstream.ToArray();
ניתן כמובן להפוך לסטרינג קריא :
String encryptedText= Convert.ToBase64String(result);
זהו... עכשיו, כדי שהצד השני יוכל לקרוא את הטקסט המוצפן, הוא צריך לקבל את הסטרינג המוצפן וכמובן את 2 הסיסמאות/מפתחות שבהם השתמשנו, שזה אחד החסרונות בהצפנה סימטרית- להעביר את המפתח לצד השני...
בהנחה שהצד השני קיבל את הטקסט המוצפן ואת המפתחות, הפעולות שהוא אמור לבצע הן כמעט זהות לתהליך ההצפנה:
ליצור את אלגוריתם ההצפנה
RijndaelManaged myAlg = new RijndaelManaged();
לאתחל אותו עם 2 המפתחות שהוא קיבל
myAlg.Key = key;
myAlg.IV = IV;
להמיר את הטקסט המוצפן למערך של בתים שוב
byte [] encrypted= Convert.Frombase64String(encryptedText);
ליצור את הזרם שממנו יקרא אובייקט ההצפנה את מערך הבתים:
MemoryStream instream = new MemoryStream (encrypted);
היכן לשמור את התוצאה:
byte [] result = new byte [instream.Length];
כעת השינוי החשוב- ניצור את אובייקט ההצפנה עם הוראה לקרוא מטקסט מוצפן:
ICryptoTransform decryptor = myAlg.CreateDecryptor();
CryptoStream decryptStream = new CryptoStream (instream, decryptor, CryptoStreamMode.Read);
ונקרא את הטקסט:
decryptStream.Read(result, 0, result.Length);
התוצאה נמצאת כעת ב result , ניתן להפוך לסטרינג שוב:
String clearText= Encoding.UTF8.GetString(result);
Download Example
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5