레지스트리에 저장할 때 암호를 암호화하는 가장 쉬운 방법은 무엇입니까?
현재는 일반 텍스트로 작성하고 있습니다 . , 사내 프로그램이라 나쁘지는 않지만 제대로하고 싶습니다. 레지스트리에 쓸 때 이것을 암호화하려면 어떻게해야하며 어떻게 해독합니까?
OurKey.SetValue("Password", textBoxPassword.Text);
인증 암호를 해독하지 않습니다!
SHA256 공급자와 같은 것을 사용하여 해시하고 도전해야 할 때 사용자의 입력을 해시하고 두 해시가 일치하는지 확인합니다.
byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString);
data = new System.Security.Cryptography.SHA256Managed().ComputeHash(data);
String hash = System.Text.Encoding.ASCII.GetString(data);
암호를 되돌릴 수있게 두는 것은 정말 끔찍한 모델입니다.
Edit2 : 나는 우리가 일선 인증에 대해 이야기하고 있다고 생각했습니다. 물론 되돌릴 수 있어야하는 다른 항목에 대해 암호를 암호화하려는 경우가 있지만 그 위에 단방향 잠금이 있어야합니다 (예외는 거의 없음).
해싱 알고리즘을 업그레이드했지만 최상의 강도를 위해 개인 솔트 를 유지 하고 해싱 하기 전에 입력에 추가 하고 싶습니다 . 비교할 때 이것을 다시 할 것입니다. 이것은 다른 레이어를 추가하여 누군가가 역전시키는 것을 더욱 어렵게 만듭니다.
해시를 "염분"하는 것도 고려해보십시오 (요리 개념이 아닙니다!). 기본적으로 이는 해시하기 전에 암호에 임의의 텍스트를 추가하는 것을 의미합니다.
" 솔트 값은 자격 증명 저장소가 손상되었을 경우 공격자가 사전 공격을 수행하는 속도를 늦추는 데 도움이되며 손상을 감지하고 대응할 추가 시간을 제공합니다. "
암호 해시를 저장하려면 :
a) 임의의 솔트 값 생성 :
byte[] salt = new byte[32];
System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);
b) 비밀번호에 솔트를 추가합니다.
// Convert the plain string pwd into bytes
byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
// Append salt to pwd before hashing
byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length);
System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);
c) 결합 된 암호 및 솔트 해시 :
// Create hash for the pwd+salt
System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
byte[] hash = hashAlgo.ComputeHash(combinedBytes);
d) 결과 해시에 솔트를 추가합니다.
// Append the salt to the hash
byte[] hashPlusSalt = new byte[hash.Length + salt.Length];
System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length);
System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);
e) 결과를 사용자 저장소 데이터베이스에 저장합니다.
이 접근 방식은 솔트를 별도로 저장 한 다음 솔트 값과 사용자로부터 얻은 일반 텍스트 암호 값을 사용하여 해시를 다시 계산할 필요가 없음을 의미합니다.
편집 : 원시 컴퓨팅 성능이 더 저렴 해지고 빨라짐에 따라 해싱 또는 솔팅 해시의 가치가 감소했습니다. Jeff Atwood는 다음과 같이 전체적으로 반복하기에는 너무 긴 훌륭한 2012 업데이트 를 제공합니다.
이것은 (솔 티드 해시 사용) 실제 보안보다 보안의 환상을 제공합니다. 해시를 생성하고 해시를 확인하기 위해 솔트와 해시 알고리즘의 선택이 모두 필요하기 때문에 공격자가 하나만 가지고있을 가능성은 거의 없습니다. 공격자가 귀하의 암호 데이터베이스를 보유 할 정도로 침해 당했다면, 그들이 귀하의 비밀스럽고 숨겨진 솔트를 가지고 있거나 얻을 수 있다고 가정하는 것이 합리적입니다.
보안의 첫 번째 규칙은 항상 최악의 상황을 가정하고 계획하는 것입니다. 소금을 사용해야합니까? 이상적으로는 각 사용자에 대해 무작위 소금을 사용해야합니까? 물론 이것은 좋은 습관이며 최소한 동일한 암호를 가진 두 명의 사용자를 명확하게 할 수 있습니다. 그러나 요즘에는 소금만으로는 비디오 카드 하드웨어에 수천 달러를 기꺼이 쓰는 사람으로부터 더 이상 당신을 구할 수 없으며 가능하다고 생각하면 문제에 처해 있습니다.
Tom Scott은 Computerphile에서 암호를 저장하는 방법 (아닌 방법)에 대한 내용을 제대로 다루었습니다.
https://www.youtube.com/watch?v=8ZtInClXe1Q
피할 수 있다면 암호를 직접 저장하지 마십시오. 대신 별도의 사전 구축 된 신뢰할 수있는 사용자 인증 플랫폼 (예 : OAuth 공급자, 회사의 Active Directory 도메인 등)을 사용하십시오.
암호를 저장해야하는 경우 여기에있는 지침을 따르지 마십시오. 적어도 선택한 언어에 적용 할 수있는 더 최근의 평판 좋은 출판물을 참조하지 않고서는 안됩니다.
여기에는 확실히 많은 똑똑한 사람들이 있으며 아마도 좋은 지침이 제공됩니다. 그러나이 글을 읽을 때 쯤이면 여기에있는 모든 답변 (이 답변 포함)이 이미 구식이 될 가능성이 높습니다.
암호를 저장하는 올바른 방법은 시간이 지남에 따라 변경됩니다.
아마도 어떤 사람들이 속옷을 갈아 입는 것보다 더 자주 할 것입니다.
즉, 잠시 동안 유용하게 사용할 수있는 몇 가지 일반적인 지침이 있습니다.
- 암호를 암호화하지 마십시오. 저장된 데이터의 복구를 허용하는 모든 저장 방법은 암호를 보관할 목적으로 본질적으로 안전하지 않습니다 (모든 형태의 암호화 포함).
생성 과정에서 사용자가 입력 한대로 정확하게 암호를 처리합니다. 암호를 암호화 모듈로 보내기 전에 암호에 대해 수행하는 모든 작업은 아마도 암호를 약화시킬 것입니다. 또한 다음 중 하나를 수행하면 암호 저장 및 확인 프로세스가 복잡해질 뿐이며, 이로 인해 향후 다른 문제 (아마도 취약점을 유발할 수도 있음)가 발생할 수 있습니다.
- 모두 대문자 / 모두 소문자로 변환하지 마십시오.
- 공백을 제거하지 마십시오.
- 허용되지 않는 문자 나 문자열을 제거하지 마십시오.
- 텍스트 인코딩을 변경하지 마십시오.
- 문자 또는 문자열 대체를 수행하지 마십시오.
- 길이에 관계없이 암호를 자르지 마십시오.
수정없이 저장할 수없는 비밀번호 생성을 거부합니다. 위의 내용을 강화합니다. 암호 저장 메커니즘이 특정 문자, 공백, 문자열 또는 암호 길이를 적절하게 처리 할 수없는 이유가있는 경우 오류를 반환하고 사용자에게 시스템의 제한 사항을 알려 해당에 맞는 암호로 다시 시도 할 수 있도록합니다. 더 나은 사용자 경험을 위해 사용자가 먼저 액세스 할 수있는 제한 목록을 만드십시오. 공격자로부터 목록을 숨기는 것은 말할 것도없고 걱정하지 마십시오. 그들은 어쨌든 스스로 쉽게 알아낼 것입니다.
- 각 계정에 대해 길고 무작위 적이며 고유 한 솔트를 사용하십시오. 암호가 실제로 동일하더라도 두 계정의 암호는 저장소에서 동일하게 보이지 않아야합니다.
- 암호와 함께 사용하도록 설계된 느리고 암호화 적으로 강력한 해싱 알고리즘을 사용합니다. MD5는 확실히 나왔습니다. SHA-1 / SHA-2는 사용할 수 없습니다. 그러나 나는 당신이 무엇을 말하지 않을거야 해야 하나 여기에 사용합니다. (이 게시물의 첫 번째 # 2 글 머리 기호를 참조하십시오.)
- 허용 할 수있는만큼 반복하십시오. 여러분의 시스템은 하루 종일 해시 암호보다 프로세서주기와 관련하여 더 좋은 일을 할 수 있지만 암호를 크래킹하는 사람들은 그렇지 않은 시스템을 가지고 있습니다. 당신에게 "너무 어렵게"만들지 않고 가능한 한 그들을 힘들게 만드십시오.
가장 중요한 것은...
여기서 누구의 말만 듣지 마십시오.
선택한 언어에 적합한 암호 저장 방법에 대한 평판이 좋은 최신 간행물을 찾아보십시오. 실제로 하나의 방법을 결정하기 전에 합의 된 여러 개별 소스에서 여러 개의 최근 간행물을 찾아야합니다.
여기에있는 모든 사람 (저를 포함하여)이 말한 모든 것이 이미 더 나은 기술로 대체되었거나 새로 개발 된 공격 방법으로 안전하지 않게 될 가능성이 매우 높습니다. 아마도 그렇지 않은 것을 찾으십시오.
이것은 당신이하고 싶은 것입니다 :
OurKey.SetValue("Password", StringEncryptor.EncryptString(textBoxPassword.Text));
OurKey.GetValue("Password", StringEncryptor.DecryptString(textBoxPassword.Text));
다음 클래스로이를 수행 할 수 있습니다. 이 클래스는 클라이언트 엔드 포인트 인 일반 클래스입니다. Ninject를 사용하여 다양한 암호화 알고리즘의 IOC를 가능하게 합니다.
public class StringEncryptor
{
private static IKernel _kernel;
static StringEncryptor()
{
_kernel = new StandardKernel(new EncryptionModule());
}
public static string EncryptString(string plainText)
{
return _kernel.Get<IStringEncryptor>().EncryptString(plainText);
}
public static string DecryptString(string encryptedText)
{
return _kernel.Get<IStringEncryptor>().DecryptString(encryptedText);
}
}
다음 클래스는 다양한 알고리즘을 주입 할 수있는 ninject 클래스입니다.
public class EncryptionModule : StandardModule
{
public override void Load()
{
Bind<IStringEncryptor>().To<TripleDESStringEncryptor>();
}
}
이것은 모든 알고리즘이 문자열을 암호화 / 복호화하기 위해 구현해야하는 인터페이스입니다.
public interface IStringEncryptor
{
string EncryptString(string plainText);
string DecryptString(string encryptedText);
}
이것은 TripleDES 알고리즘을 사용한 구현입니다.
public class TripleDESStringEncryptor : IStringEncryptor
{
private byte[] _key;
private byte[] _iv;
private TripleDESCryptoServiceProvider _provider;
public TripleDESStringEncryptor()
{
_key = System.Text.ASCIIEncoding.ASCII.GetBytes("GSYAHAGCBDUUADIADKOPAAAW");
_iv = System.Text.ASCIIEncoding.ASCII.GetBytes("USAZBGAW");
_provider = new TripleDESCryptoServiceProvider();
}
#region IStringEncryptor Members
public string EncryptString(string plainText)
{
return Transform(plainText, _provider.CreateEncryptor(_key, _iv));
}
public string DecryptString(string encryptedText)
{
return Transform(encryptedText, _provider.CreateDecryptor(_key, _iv));
}
#endregion
private string Transform(string text, ICryptoTransform transform)
{
if (text == null)
{
return null;
}
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
byte[] input = Encoding.Default.GetBytes(text);
cryptoStream.Write(input, 0, input.Length);
cryptoStream.FlushFinalBlock();
return Encoding.Default.GetString(stream.ToArray());
}
}
}
}
내 비디오를보고 이에 대한 코드를 다운로드 할 수 있습니다. http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html
한 가지 옵션은 일반 텍스트 암호 대신 암호의 해시 (SHA1, MD5)를 저장하고 암호가 좋은지 확인하려면 해당 해시와 비교하는 것입니다.
보안 저장소 (예 : 서비스에 연결하는 데 사용할 암호)가 필요한 경우 문제가 더 복잡합니다.
인증만을위한 것이라면 해시를 사용하는 것으로 충분합니다.
If you want to be able to decrypt the password, I think the easiest way would be to use DPAPI (user store mode) to encrypt/decrypt. This way you don't have to fiddle with encryption keys, store them somewhere or hard-code them in your code - in both cases somebody can discover them by looking into registry, user settings or using Reflector.
Otherwise use hashes SHA1 or MD5 like others have said here.
Like ligget78 said, DPAPI would be a good way to go for storing passwords. Check out the ProtectedData class on MSDN for example usage.
I have looked all over for a good example of encryption and decryption process but most were overly complex.
Anyhow there are many reasons someone may want to decrypt some text values including passwords. The reason I need to decrypt the password on the site I am working on currently is because they want to make sure when someone is forced to change their password when it expires that we do not let them change it with a close variant of the same password they used in the last x months.
So I wrote up a process that will do this in a simplified manner. I hope this code is beneficial to someone. For all I know I may end up using this at another time for a different company/site.
public string GenerateAPassKey(string passphrase)
{
// Pass Phrase can be any string
string passPhrase = passphrase;
// Salt Value can be any string(for simplicity use the same value as used for the pass phrase)
string saltValue = passphrase;
// Hash Algorithm can be "SHA1 or MD5"
string hashAlgorithm = "SHA1";
// Password Iterations can be any number
int passwordIterations = 2;
// Key Size can be 128,192 or 256
int keySize = 256;
// Convert Salt passphrase string to a Byte Array
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
// Using System.Security.Cryptography.PasswordDeriveBytes to create the Key
PasswordDeriveBytes pdb = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);
//When creating a Key Byte array from the base64 string the Key must have 32 dimensions.
byte[] Key = pdb.GetBytes(keySize / 11);
String KeyString = Convert.ToBase64String(Key);
return KeyString;
}
//Save the keystring some place like your database and use it to decrypt and encrypt
//any text string or text file etc. Make sure you dont lose it though.
private static string Encrypt(string plainStr, string KeyString)
{
RijndaelManaged aesEncryption = new RijndaelManaged();
aesEncryption.KeySize = 256;
aesEncryption.BlockSize = 128;
aesEncryption.Mode = CipherMode.ECB;
aesEncryption.Padding = PaddingMode.ISO10126;
byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
aesEncryption.Key = KeyInBytes;
byte[] plainText = ASCIIEncoding.UTF8.GetBytes(plainStr);
ICryptoTransform crypto = aesEncryption.CreateEncryptor();
byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherText);
}
private static string Decrypt(string encryptedText, string KeyString)
{
RijndaelManaged aesEncryption = new RijndaelManaged();
aesEncryption.KeySize = 256;
aesEncryption.BlockSize = 128;
aesEncryption.Mode = CipherMode.ECB;
aesEncryption.Padding = PaddingMode.ISO10126;
byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
aesEncryption.Key = KeyInBytes;
ICryptoTransform decrypto = aesEncryption.CreateDecryptor();
byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);
return ASCIIEncoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length));
}
String KeyString = GenerateAPassKey("PassKey");
String EncryptedPassword = Encrypt("25Characterlengthpassword!", KeyString);
String DecryptedPassword = Decrypt(EncryptedPassword, KeyString);
If it's a password used for authentication by your application, then hash the password as others suggest.
If you're storing passwords for an external resource, you'll often want to be able to prompt the user for these credentials and give him the opportunity to save them securely. Windows provides the Credentials UI (CredUI) for this purpose - there are a number of samples showing how to use this in .NET, including this one on MSDN.
If you need more than this, for example securing a connection string (for connection to a database), check this article, as it provides the best "option" for this.
Oli's answer is also good, as it shows how you can create a hash for a string.
..NET provides cryptographics services in class contained in the System.Security.Cryptography namespace.
Rather than encrypt/decrypt, you should be passing the password through a hashing algorithm, md5/sha512, or similar. What you would ideally do is hash the password and store the hash, then when the password is needed, you hash the entry and compare the entries. A password will then never be "decrypted", simply hashed and then compared.
'Program Tip' 카테고리의 다른 글
IIS의 ASP.NET MVC3 및 Windows Auth가 계속 / Account / Login으로 리디렉션됩니다. (0) | 2020.12.13 |
---|---|
NSDictionary를 NSString으로 변환 (0) | 2020.12.13 |
Java에서 임의의 색상을 만드시겠습니까? (0) | 2020.12.13 |
교리 2 ArrayCollection 필터 방법 (0) | 2020.12.13 |
두 개의 HTML 표 셀 병합 (0) | 2020.12.13 |