代码拉取完成,页面将自动刷新
/*
* Copyright (C) 2013 Colin Mackie.
* This software is distributed under the terms of the GNU General Public License.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;
using System.Web;
using System.Windows;
using System.Windows.Forms;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Win32;
using WinAuth.Resources;
namespace WinAuth
{
/// <summary>
/// Class proving helper functions to save data for application
/// </summary>
class WinAuthHelper
{
/// <summary>
/// Registry key for application
/// </summary>
public const string WINAUTHREGKEY = @"Software\WinAuth3";
/// <summary>
/// Registry key for application
/// </summary>
private const string WINAUTH2REGKEY = @"Software\WinAuth";
/// <summary>
/// Registry data name for last loaded file
/// </summary>
private const string WINAUTHREGKEY_LASTFILE = @"File{0}";
/// <summary>
/// Registry data name for last good
/// </summary>
private const string WINAUTHREGKEY_BACKUP = @"Software\WinAuth3\Backup";
/// <summary>
/// Encrpyted config backup
/// </summary>
private const string WINAUTHREGKEY_CONFIGBACKUP = @"Software\WinAuth3\Backup\Config";
/// <summary>
/// Registry data name for errors
/// </summary>
private const string WINAUTHREGKEY_ERROR = @"Software\WinAuth3\Error";
/// <summary>
/// Registry key for starting with windows
/// </summary>
private const string RUNKEY = @"Software\Microsoft\Windows\CurrentVersion\Run";
/// <summary>
/// Name of application config file for 1.3
/// </summary>
public const string CONFIG_FILE_NAME_1_3 = "winauth.xml";
/// <summary>
/// Name of default authenticator file
/// </summary>
public const string DEFAULT_AUTHENTICATOR_FILE_NAME = "winauth.xml";
/// <summary>
/// The WinAuth PGP public key
/// </summary>
public const string WINAUTH_PGP_PUBLICKEY =
@"-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.7.4114.6375
mQEMBFA8sxQBCAC5EWjbGHDgyo4e9rcwse1mWbCOyeTwGZH2malJreF2v81KwBZa
eCAPX6cP6EWJPlMOgkJpBQOgh+AezkYEidrW4+NXCGv+Z03U1YBc7e/nYnABZrJx
XsqWVyM3d3iLSpKsMfk2OAIAIvoCvzcdx0ljm2IXGKRHGnc0nU7hSFXh5S/sJErN
Cgrll6lD2CPNIPuUiMSWptgO1RAjerk0rwLh1DSChicPMJZfxJWn7JD1VVQLmAon
EJ4x0MUIbff7ZmEna4O2rF9mrCjwfANkcz8N6WFp3PrfhxArXkvOBPYF9iEigFRS
QVt6XAF6sjGhSYxZRaRj0tE4PyajE/HfNk0DAAkBAbQbV2luQXV0aCA8d2luYXV0
aEBnbWFpbC5jb20+iQE0BBABAgASBQJQPRWEApsPAhYBAhUCAgsDABYJEJ3DDyNp
qwwqApsPAhYBAhUCAgsDqb8IAKJRlRu5ne2BuHrMlKW/BI6I/hpkGQ8BzmO7LatM
YYj//XKkbQ2BSvbDNI1al5HSo1iseokIZqD07iMwsp9GvLXSOVCROK9HYJ4dHsdP
l68KgNDWu8ZDhPRGerf4+pn1jRfXW4NdFT8W1TX3RArpdVSd5Q2tV2tZrANErBYa
UTDodsNKwikcgk89a2NI+Lh17lFGCFdAdZ07gRwu6cOm4SqP2TjWjDreXqlE9fHd
0dwmYeS1QlGYK3ETNS1KvVTNaKdht231jGwlxy09Rxtx1EBLqFNsc+BW5rjYEPN2
EAlelUJsVidUjZNB1ySm9uW8xurSEXWPZxWITl+LYmgwtn0=
=dvwu
-----END PGP PUBLIC KEY BLOCK-----";
/// <summary>
/// Load the authenticator and configuration settings
/// </summary>
/// <param name="form">parent winform</param>
/// <param name="configFile">name of configfile or null for auto</param>
/// <param name="password">optional supplied password or null to prompt if necessatu</param>
/// <returns>new WinAuthConfig settings</returns>
public static WinAuthConfig LoadConfig(Form form, string configFile, string password = null)
{
WinAuthConfig config = new WinAuthConfig();
if (string.IsNullOrEmpty(password) == false)
{
config.Password = password;
}
if (string.IsNullOrEmpty(configFile) == true)
{
// check for file in current directory
configFile = Path.Combine(Environment.CurrentDirectory, DEFAULT_AUTHENTICATOR_FILE_NAME);
if (File.Exists(configFile) == false)
{
configFile = null;
}
}
if (string.IsNullOrEmpty(configFile) == true)
{
// check for file in exe directory
configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), DEFAULT_AUTHENTICATOR_FILE_NAME);
if (File.Exists(configFile) == false)
{
configFile = null;
}
}
if (string.IsNullOrEmpty(configFile) == true)
{
// do we have a file specific in the registry?
string configDirectory = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), WinAuthMain.APPLICATION_NAME);
// check for default authenticator
configFile = Path.Combine(configDirectory, DEFAULT_AUTHENTICATOR_FILE_NAME);
// if no config file, just return a blank config
if (File.Exists(configFile) == false)
{
return config;
}
}
// if no config file when one was specified; report an error
if (File.Exists(configFile) == false)
{
//MessageBox.Show(form,
// strings.CannotFindConfigurationFile + ": " + configFile,
// form.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
// return config;
throw new ApplicationException(strings.CannotFindConfigurationFile + ": " + configFile);
}
// check if readonly
FileInfo fi = new FileInfo(configFile);
if (fi.Exists && fi.IsReadOnly)
{
config.IsReadOnly = true;
}
bool changed = false;
try
{
var data = File.ReadAllBytes(configFile);
if (data.Length == 0 || data[0] == 0)
{
// switch to backup
if (File.Exists(configFile + ".bak") == true)
{
data = File.ReadAllBytes(configFile + ".bak");
if (data.Length != 0 && data[0] != 0)
{
File.WriteAllBytes(configFile, data);
}
}
}
using (FileStream fs = new FileStream(configFile, FileMode.Open, FileAccess.Read))
{
XmlReader reader = XmlReader.Create(fs);
changed = config.ReadXml(reader, password);
}
config.Filename = configFile;
if (config.Version < WinAuthConfig.CURRENTVERSION)
{
// set new created values
foreach (WinAuthAuthenticator wa in config)
{
wa.Created = fi.CreationTime;
}
config.Upgraded = true;
}
if (changed == true && config.IsReadOnly == false)
{
SaveConfig(config);
}
}
catch (EncryptedSecretDataException )
{
// we require a password
throw;
}
catch (BadPasswordException)
{
// we require a password
throw;
}
catch (Exception )
{
throw;
}
SaveToRegistry(config);
return config;
}
/// <summary>
/// Return any 2.x authenticator entry in the registry
/// </summary>
/// <returns></returns>
public static string GetLastV2Config()
{
// check for a v2 last file entry
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(WINAUTH2REGKEY, false))
{
string lastfile;
if (key != null
&& (lastfile = key.GetValue(string.Format(CultureInfo.InvariantCulture, WINAUTHREGKEY_LASTFILE, 1), null) as string) != null
&& File.Exists(lastfile) == true)
{
return lastfile;
}
}
}
catch (System.Security.SecurityException) { }
return null;
}
/// <summary>
/// Save the authenticator
/// </summary>
/// <param name="configFile">filename to save to</param>
/// <param name="config">current settings to save</param>
public static void SaveConfig(WinAuthConfig config)
{
// create the xml
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.UTF8;
// Issue 41 (http://code.google.com/p/winauth/issues/detail?id=41): saving may crash leaving file corrupt, so write into memory stream first before an atomic file write
using (MemoryStream ms = new MemoryStream())
{
// save config into memory
using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
config.WriteXmlString(writer);
}
// if no config file yet, use default
if (string.IsNullOrEmpty(config.Filename) == true)
{
string configDirectory = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), WinAuthMain.APPLICATION_NAME);
Directory.CreateDirectory(configDirectory);
config.Filename = Path.Combine(configDirectory, DEFAULT_AUTHENTICATOR_FILE_NAME);
}
FileInfo fi = new FileInfo(config.Filename);
if (!fi.Exists || !fi.IsReadOnly)
{
// write memory stream to file
try
{
byte[] data = ms.ToArray();
// getting instance of zerod files, so do some sanity checks
if (data.Length == 0 || data[0] == 0)
{
throw new ApplicationException("Zero data when saving config");
}
var tempfile = config.Filename + ".tmp";
File.WriteAllBytes(tempfile, data);
// read it back
var verify = File.ReadAllBytes(tempfile);
if (verify.Length != data.Length || verify.SequenceEqual(data) == false)
{
throw new ApplicationException("Save config doesn't compare with memory: " + Convert.ToBase64String(data));
}
// move it to old file
File.Delete(config.Filename + ".bak");
if (File.Exists(config.Filename) == true)
{
File.Move(config.Filename, config.Filename + ".bak");
}
File.Move(tempfile, config.Filename);
}
catch (UnauthorizedAccessException )
{
// fail silently if read only
if (fi.IsReadOnly)
{
config.IsReadOnly = true;
return;
}
throw;
}
}
}
}
/// <summary>
/// Save a PGP encrypted version of the config into the registry for recovery
///
/// Issue#133: this just compounds each time we load, and is really pointless so we are removing it
/// but in the meantime we have to clear it out
/// </summary>
/// <param name="config"></param>
private static void SaveToRegistry(WinAuthConfig config)
{
config.WriteSetting(WINAUTHREGKEY_CONFIGBACKUP, null);
}
/// <summary>
/// Save a PGP encrypted version of an authenticator into the registry for recovery
/// </summary>
/// <param name="wa">WinAuthAuthenticator instance</param>
public static void SaveToRegistry(WinAuthConfig config, WinAuthAuthenticator wa)
{
if (config == null || wa == null || wa.AuthenticatorData == null)
{
return;
}
using (HashAlgorithm sha = Authenticator.SafeHasher("SHA256"))
{
// get a hash based on the authenticator key
string authkey = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(wa.AuthenticatorData.SecretData)));
// save the PGP encrypted key
using (EncodedStringWriter sw = new EncodedStringWriter(Encoding.UTF8))
{
XmlWriterSettings xmlsettings = new XmlWriterSettings();
xmlsettings.Indent = true;
using (XmlWriter xw = XmlWriter.Create(sw, xmlsettings))
{
xw.WriteStartElement("WinAuth");
xw.WriteAttributeString("version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(2));
wa.WriteXmlString(xw);
xw.WriteEndElement();
}
string pgpkey = string.IsNullOrEmpty(config.PGPKey) == false ? config.PGPKey : WinAuthHelper.WINAUTH_PGP_PUBLICKEY;
config.WriteSetting(WINAUTHREGKEY_BACKUP + "\\" + authkey, PGPEncrypt(sw.ToString(), pgpkey));
}
}
}
/// <summary>
/// Read the encrpyted backup registry entries to be sent within the diagnostics report
/// </summary>
public static string ReadBackupFromRegistry(WinAuthConfig config)
{
StringBuilder buffer = new StringBuilder();
foreach (string name in config.ReadSettingKeys(WINAUTHREGKEY_BACKUP))
{
object val = ReadRegistryValue(name);
if (val != null)
{
buffer.Append(name + "=" + Convert.ToString(val)).Append(Environment.NewLine);
}
}
return buffer.ToString();
}
/// <summary>
/// Set up winauth so it will start with Windows by adding entry into registry
/// </summary>
/// <param name="enabled">enable or disable start with windows</param>
public static void SetStartWithWindows(bool enabled)
{
if (enabled == true)
{
// get path of exe and minimize flag
WriteRegistryValue(RUNKEY + "\\" + WinAuthMain.APPLICATION_NAME, Application.ExecutablePath + " -min");
}
else
{
DeleteRegistryKey(RUNKEY + "\\" + WinAuthMain.APPLICATION_NAME);
}
}
/// <summary>
/// Import a file containing authenticators in the KeyUriFormat. The file might be plain text, encrypted zip or encrypted pgp.
/// </summary>
/// <param name="parent">parent Form</param>
/// <param name="file">file name to import</param>
/// <returns>list of imported authenticators</returns>
public static List<WinAuthAuthenticator> ImportAuthenticators(Form parent, string file)
{
List<WinAuthAuthenticator> authenticators = new List<WinAuthAuthenticator>();
string password = null;
string pgpKey = null;
StringBuilder lines = new StringBuilder();
bool retry;
do
{
retry = false;
lines.Length = 0;
// open the zip file
if (string.Compare(Path.GetExtension(file), ".zip", true) == 0)
{
using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
ZipFile zip = null;
try
{
zip = new ZipFile(fs);
if (string.IsNullOrEmpty(password) == false)
{
zip.Password = password;
}
byte[] buffer = new byte[4096];
foreach (ZipEntry entry in zip)
{
if (entry.IsFile == false || string.Compare(Path.GetExtension(entry.Name), ".txt", true) != 0)
{
continue;
}
// read file out
Stream zs = zip.GetInputStream(entry);
using (var ms = new MemoryStream())
{
StreamUtils.Copy(zs, ms, buffer);
// get as string and append
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms))
{
lines.Append(sr.ReadToEnd()).Append(Environment.NewLine);
}
}
}
}
catch (ZipException ex)
{
if (ex.Message.IndexOf("password") != -1)
{
// already have a password
if (string.IsNullOrEmpty(password) == false)
{
WinAuthForm.ErrorDialog(parent, strings.InvalidPassword, ex.InnerException, MessageBoxButtons.OK);
}
// need password
GetPasswordForm form = new GetPasswordForm();
if (form.ShowDialog(parent) == DialogResult.Cancel)
{
return null;
}
password = form.Password;
retry = true;
continue;
}
throw;
}
finally
{
if (zip != null)
{
zip.IsStreamOwner = true;
zip.Close();
}
}
}
}
else if (string.Compare(Path.GetExtension(file), ".pgp", true) == 0)
{
string encoded = File.ReadAllText(file);
if (string.IsNullOrEmpty(pgpKey) == true)
{
// need password
GetPGPKeyForm form = new GetPGPKeyForm();
if (form.ShowDialog(parent) == DialogResult.Cancel)
{
return null;
}
pgpKey = form.PGPKey;
password = form.Password;
retry = true;
continue;
}
try
{
string line = PGPDecrypt(encoded, pgpKey, password);
lines.Append(line);
}
catch (Exception ex)
{
WinAuthForm.ErrorDialog(parent, strings.InvalidPassword, ex.InnerException, MessageBoxButtons.OK);
pgpKey = null;
password = null;
retry = true;
continue;
}
}
else // read a plain text file
{
lines.Append(File.ReadAllText(file));
}
} while (retry);
int linenumber = 0;
try
{
using (var sr = new StringReader(lines.ToString()))
{
string line;
while ((line = sr.ReadLine()) != null)
{
linenumber++;
// ignore blank lines or comments
line = line.Trim();
if (line.Length == 0 || line.IndexOf("#") == 0)
{
continue;
}
// bug if there is a hash before ?
var hash = line.IndexOf("#");
var qm = line.IndexOf("?");
if (hash != -1 && hash < qm)
{
line = line.Substring(0, hash) + "%23" + line.Substring(hash + 1);
}
// parse and validate URI
var uri = new Uri(line);
// we only support "otpauth"
if (uri.Scheme != "otpauth")
{
throw new ApplicationException("Import only supports otpauth://");
}
// we only support totp (not hotp)
if (uri.Host != "totp" && uri.Host != "hotp")
{
throw new ApplicationException("Import only supports otpauth://totp/ or otpauth://hotp/");
}
// get the label and optional issuer
string issuer = string.Empty;
string label = (string.IsNullOrEmpty(uri.LocalPath) == false ? uri.LocalPath.Substring(1) : string.Empty); // skip past initial /
int p = label.IndexOf(":");
if (p != -1)
{
issuer = label.Substring(0, p);
label = label.Substring(p + 1);
}
// + aren't decoded
label = label.Replace("+", " ");
var query = HttpUtility.ParseQueryString(uri.Query);
string secret = query["secret"];
if (string.IsNullOrEmpty(secret) == true)
{
throw new ApplicationException("Authenticator does not contain secret");
}
string counter = query["counter"];
if (uri.Host == "hotp" && string.IsNullOrEmpty(counter) == true)
{
throw new ApplicationException("HOTP authenticator should have a counter");
}
WinAuthAuthenticator importedAuthenticator = new WinAuthAuthenticator();
importedAuthenticator.AutoRefresh = false;
//
Authenticator auth;
if (string.Compare(issuer, "BattleNet", true) == 0)
{
string serial = query["serial"];
if (string.IsNullOrEmpty(serial) == true)
{
throw new ApplicationException("Battle.net Authenticator does not have a serial");
}
serial = serial.ToUpper();
if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
{
throw new ApplicationException("Invalid serial for Battle.net Authenticator");
}
auth = new BattleNetAuthenticator();
//char[] decoded = Base32.getInstance().Decode(secret).Select(c => Convert.ToChar(c)).ToArray(); // this is hex string values
//string hex = new string(decoded);
//((BattleNetAuthenticator)auth).SecretKey = Authenticator.StringToByteArray(hex);
((BattleNetAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
((BattleNetAuthenticator)auth).Serial = serial;
issuer = string.Empty;
}
else if (string.Compare(issuer, "Steam", true) == 0)
{
auth = new SteamAuthenticator();
((SteamAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
((SteamAuthenticator)auth).Serial = string.Empty;
((SteamAuthenticator)auth).DeviceId = query["deviceid"] ?? string.Empty;
((SteamAuthenticator)auth).SteamData = query["data"] ?? string.Empty;
issuer = string.Empty;
}
else if (uri.Host == "hotp")
{
auth = new HOTPAuthenticator();
((HOTPAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
((HOTPAuthenticator)auth).Counter = int.Parse(counter);
if (string.IsNullOrEmpty(issuer) == false)
{
auth.Issuer = issuer;
}
}
else // if (string.Compare(issuer, "Google", true) == 0)
{
auth = new GoogleAuthenticator();
((GoogleAuthenticator)auth).Enroll(secret);
if (string.Compare(issuer, "Google", true) == 0)
{
issuer = string.Empty;
}
else if (string.IsNullOrEmpty(issuer) == false)
{
auth.Issuer = issuer;
}
}
int period = 0;
int.TryParse(query["period"], out period);
if (period != 0)
{
auth.Period = period;
}
int digits = 0;
int.TryParse(query["digits"], out digits);
if (digits != 0)
{
auth.CodeDigits = digits;
}
Authenticator.HMACTypes hmactype;
#if NETFX_3
try
{
hmactype = (WinAuth.Authenticator.HMACTypes)Enum.Parse(typeof(WinAuth.Authenticator.HMACTypes), query["algorithm"], true);
auth.HMACType = hmactype;
}
catch (Exception) { }
#else
if (Enum.TryParse<Authenticator.HMACTypes>(query["algorithm"], true, out hmactype) == true)
{
auth.HMACType = hmactype;
}
#endif
//
if (label.Length != 0)
{
importedAuthenticator.Name = (issuer.Length != 0 ? issuer + " (" + label + ")" : label);
}
else if (issuer.Length != 0)
{
importedAuthenticator.Name = issuer;
}
else
{
importedAuthenticator.Name = "Imported";
}
//
importedAuthenticator.AuthenticatorData = auth;
// set the icon
string icon = query["icon"];
if (string.IsNullOrEmpty(icon) == false)
{
if (icon.StartsWith("base64:") == true)
{
string b64 = Convert.ToBase64String(Base32.getInstance().Decode(icon.Substring(7)));
importedAuthenticator.Skin = "base64:" + b64;
}
else
{
importedAuthenticator.Skin = icon + "Icon.png";
}
}
// sync
importedAuthenticator.Sync();
authenticators.Add(importedAuthenticator);
}
}
return authenticators;
}
catch (UriFormatException ex)
{
throw new ImportException(string.Format(strings.ImportInvalidUri, linenumber), ex);
}
catch (Exception ex)
{
throw new ImportException(string.Format(strings.ImportError, linenumber, ex.Message), ex);
}
}
public static void ExportAuthenticators(Form form, IList<WinAuthAuthenticator> authenticators, string file, string password, string pgpKey)
{
// create file in memory
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
{
List<WinAuthAuthenticator> unprotected = new List<WinAuthAuthenticator>();
foreach (var auth in authenticators)
{
// unprotect if necessary
if (auth.AuthenticatorData.RequiresPassword == true)
{
// request the password
UnprotectPasswordForm getPassForm = new UnprotectPasswordForm();
getPassForm.Authenticator = auth;
DialogResult result = getPassForm.ShowDialog(form);
if (result == DialogResult.OK)
{
unprotected.Add(auth);
}
else
{
continue;
}
}
string line = auth.ToUrl();
sw.WriteLine(line);
}
// reprotect
foreach (var auth in unprotected)
{
auth.AuthenticatorData.Protect();
}
// reset and write stream out to disk or as zip
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
// reset and write stream out to disk or as zip
if (string.Compare(Path.GetExtension(file), ".zip", true) == 0)
{
using (var zip = new ZipOutputStream(new FileStream(file, FileMode.Create, FileAccess.Write)))
{
if (string.IsNullOrEmpty(password) == false)
{
zip.Password = password;
}
zip.IsStreamOwner = true;
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(Path.GetFileNameWithoutExtension(file) + ".txt"));
entry.DateTime = DateTime.Now;
zip.UseZip64 = UseZip64.Off;
zip.PutNextEntry(entry);
byte[] buffer = new byte[4096];
StreamUtils.Copy(ms, zip, buffer);
zip.CloseEntry();
}
}
else if (string.IsNullOrEmpty(pgpKey) == false)
{
using (var sr = new StreamReader(ms))
{
var plain = sr.ReadToEnd();
string encoded = PGPEncrypt(plain, pgpKey);
File.WriteAllText(file, encoded);
}
}
else
{
using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write))
{
byte[] buffer = new byte[4096];
StreamUtils.Copy(ms, fs, buffer);
}
}
}
}
}
#region HttpUtility
/// <summary>
/// Our own version of HtmlEncode replacing HttpUtility.HtmlEncode so we can remove the System.Web reference
/// which isn't available in the .Net client profile
/// </summary>
/// <param name="text">text to be encoded</param>
/// <returns>encoded string</returns>
public static string HtmlEncode(string text)
{
if (string.IsNullOrEmpty(text) == true)
{
return text;
}
StringBuilder sb = new StringBuilder(text.Length);
int len = text.Length;
for (int i = 0; i < len; i++)
{
switch (text[i])
{
case '<':
sb.Append("<");
break;
case '>':
sb.Append(">");
break;
case '"':
sb.Append(""");
break;
case '&':
sb.Append("&");
break;
default:
if (text[i] > 159)
{
// decimal numeric entity
sb.Append("&#");
sb.Append(((int)text[i]).ToString(CultureInfo.InvariantCulture));
sb.Append(";");
}
else
{
sb.Append(text[i]);
}
break;
}
}
return sb.ToString();
}
/// <summary>
/// Our own version of HttpUtility.ParseQueryString so we can remove the reference to System.Web
/// which is not available in client profile.
/// </summary>
/// <param name="qs">string query string</param>
/// <returns>collection of name value pairs</returns>
public static NameValueCollection ParseQueryString(string qs)
{
NameValueCollection pairs = new NameValueCollection();
// ignore blanks and remove initial "?"
if (string.IsNullOrEmpty(qs) == true)
{
return pairs;
}
if (qs.StartsWith("?") == true)
{
qs = qs.Substring(1);
}
// get each a=b&... key-value pair
foreach (string p in qs.Split('&'))
{
string[] keypair = p.Split('=');
string key = keypair[0];
string v = (keypair.Length >= 2 ? keypair[1] : null);
if (string.IsNullOrEmpty(v) == false)
{
// decode (without using System.Web)
string newv;
while ((newv = Uri.UnescapeDataString(v)) != v)
{
v = newv;
}
}
pairs.Add(key, v);
}
return pairs;
}
#endregion
#region Registry Function
/// <summary>
/// Read a value from a registry key, e.g. Software\WinAuth3\BetValue. Return defaultValue
/// if key does not exist or there is a security exception
///
/// The key name can conjtain the explicit root, e.g. "HKEY_LOCAL_MACHINE\Software..." otherwise
/// HKEY_CURRENT_USER is assumed.
/// </summary>
/// <param name="keyname">full key name</param>
/// <param name="defaultValue">default value</param>
/// <returns>key value or default value</returns>
public static object ReadRegistryValue(string keyname, object defaultValue = null)
{
RegistryKey basekey;
List<string> keyparts = keyname.Split('\\').ToList();
switch (keyparts[0])
{
case "HKEY_CLASSES_ROOT":
basekey = Registry.ClassesRoot;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_CONFIG":
basekey = Registry.CurrentConfig;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_USER":
basekey = Registry.CurrentUser;
keyparts.RemoveAt(0);
break;
case "HKEY_LOCAL_MACHINE":
basekey = Registry.LocalMachine;
keyparts.RemoveAt(0);
break;
case "HKEY_PERFORMANCE_DATA":
basekey = Registry.PerformanceData;
keyparts.RemoveAt(0);
break;
default:
basekey = Registry.CurrentUser;
break;
}
string subkey = string.Join("\\", keyparts.Take(keyparts.Count - 1).ToArray());
string valuekey = keyparts[keyparts.Count - 1];
try
{
using (RegistryKey key = basekey.OpenSubKey(subkey))
{
return (key != null ? key.GetValue(valuekey, defaultValue) : defaultValue);
}
}
catch (System.Security.SecurityException)
{
return defaultValue;
}
}
/// <summary>
/// Get the names of all the child value keys for a given parent.
/// </summary>
/// <param name="keyname">name of parent key</param>
/// <returns>string array of all child value names or empty array</returns>
public static string[] ReadRegistryKeys(string keyname)
{
RegistryKey basekey;
List<string> keyparts = keyname.Split('\\').ToList();
switch (keyparts[0])
{
case "HKEY_CLASSES_ROOT":
basekey = Registry.ClassesRoot;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_CONFIG":
basekey = Registry.CurrentConfig;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_USER":
basekey = Registry.CurrentUser;
keyparts.RemoveAt(0);
break;
case "HKEY_LOCAL_MACHINE":
basekey = Registry.LocalMachine;
keyparts.RemoveAt(0);
break;
case "HKEY_PERFORMANCE_DATA":
basekey = Registry.PerformanceData;
keyparts.RemoveAt(0);
break;
default:
basekey = Registry.CurrentUser;
break;
}
string subkey = string.Join("\\", keyparts.ToArray());
try
{
using (RegistryKey key = basekey.OpenSubKey(subkey))
{
if (key == null)
{
return new string[0];
}
// get all value names
List<string> keys = key.GetValueNames().ToList();
for (int i = 0; i < keys.Count; i++)
{
keys[i] = keyname + "\\" + keys[i];
}
// read any subkeys
if (key.SubKeyCount != 0)
{
foreach (string subkeyname in key.GetSubKeyNames())
{
keys.AddRange(ReadRegistryKeys(keyname + "\\" + subkeyname));
}
}
return keys.ToArray();
}
}
catch (System.Security.SecurityException)
{
return new string[0];
}
}
/// <summary>
/// Write a value into a registry key value.
/// </summary>
/// <param name="keyname">full name of key</param>
/// <param name="value">value to write</param>
public static void WriteRegistryValue(string keyname, object value)
{
RegistryKey basekey;
List<string> keyparts = keyname.Split('\\').ToList();
switch (keyparts[0])
{
case "HKEY_CLASSES_ROOT":
basekey = Registry.ClassesRoot;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_CONFIG":
basekey = Registry.CurrentConfig;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_USER":
basekey = Registry.CurrentUser;
keyparts.RemoveAt(0);
break;
case "HKEY_LOCAL_MACHINE":
basekey = Registry.LocalMachine;
keyparts.RemoveAt(0);
break;
case "HKEY_PERFORMANCE_DATA":
basekey = Registry.PerformanceData;
keyparts.RemoveAt(0);
break;
default:
basekey = Registry.CurrentUser;
break;
}
string subkey = string.Join("\\", keyparts.Take(keyparts.Count - 1).ToArray());
string valuekey = keyparts[keyparts.Count - 1];
try
{
using (RegistryKey key = basekey.CreateSubKey(subkey))
{
key.SetValue(valuekey, value);
}
}
catch (System.Security.SecurityException)
{
return;
}
}
/// <summary>
/// Delete a registry entry value or key. If it is deleted and there are no more sibling values or subkeys,
/// the parent is also removed.
/// </summary>
/// <param name="keyname"></param>
public static void DeleteRegistryKey(string keyname)
{
RegistryKey basekey;
List<string> keyparts = keyname.Split('\\').ToList();
switch (keyparts[0])
{
case "HKEY_CLASSES_ROOT":
basekey = Registry.ClassesRoot;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_CONFIG":
basekey = Registry.CurrentConfig;
keyparts.RemoveAt(0);
break;
case "HKEY_CURRENT_USER":
basekey = Registry.CurrentUser;
keyparts.RemoveAt(0);
break;
case "HKEY_LOCAL_MACHINE":
basekey = Registry.LocalMachine;
keyparts.RemoveAt(0);
break;
case "HKEY_PERFORMANCE_DATA":
basekey = Registry.PerformanceData;
keyparts.RemoveAt(0);
break;
default:
basekey = Registry.CurrentUser;
break;
}
string subkey = string.Join("\\", keyparts.Take(keyparts.Count - 1).ToArray());
string valuekey = keyparts[keyparts.Count - 1];
try
{
using (RegistryKey key = basekey.CreateSubKey(subkey))
{
if (key != null)
{
if (key.GetValueNames().Contains(valuekey) == true)
{
key.DeleteValue(valuekey, false);
}
if (key.GetSubKeyNames().Contains(valuekey) == true)
{
#if NETFX_4
key.DeleteSubKeyTree(valuekey, false);
#endif
#if NETFX_3
key.DeleteSubKeyTree(valuekey);
#endif
}
// if the parent now has no values, we can remove it too
if (key.SubKeyCount == 0 && key.ValueCount == 0)
{
basekey.DeleteSubKey(subkey, false);
}
}
}
}
catch (System.Security.SecurityException)
{
return;
}
}
#endregion
#region PGP functions
/// <summary>
/// Build a PGP key pair
/// </summary>
/// <param name="bits">number of bits in key, e.g. 2048</param>
/// <param name="identifier">key identifier, e.g. "Your Name <your@emailaddress.com>" </param>
/// <param name="password">key password or null</param>
/// <param name="privateKey">returned ascii private key</param>
/// <param name="publicKey">returned ascii public key</param>
public static void PGPGenerateKey(int bits, string identifier, string password, out string privateKey, out string publicKey)
{
// generate a new RSA keypair
RsaKeyPairGenerator gen = new RsaKeyPairGenerator();
gen.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(0x101), new Org.BouncyCastle.Security.SecureRandom(), bits, 80));
AsymmetricCipherKeyPair pair = gen.GenerateKeyPair();
// create PGP subpacket
PgpSignatureSubpacketGenerator hashedGen = new PgpSignatureSubpacketGenerator();
hashedGen.SetKeyFlags(true, PgpKeyFlags.CanCertify | PgpKeyFlags.CanSign | PgpKeyFlags.CanEncryptCommunications | PgpKeyFlags.CanEncryptStorage);
hashedGen.SetPreferredCompressionAlgorithms(false, new int[] { (int)CompressionAlgorithmTag.Zip });
hashedGen.SetPreferredHashAlgorithms(false, new int[] { (int)HashAlgorithmTag.Sha1 });
hashedGen.SetPreferredSymmetricAlgorithms(false, new int[] { (int)SymmetricKeyAlgorithmTag.Cast5 });
PgpSignatureSubpacketVector sv = hashedGen.Generate();
PgpSignatureSubpacketGenerator unhashedGen = new PgpSignatureSubpacketGenerator();
// create the PGP key
PgpSecretKey secretKey = new PgpSecretKey(
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
pair.Public,
pair.Private,
DateTime.Now,
identifier,
SymmetricKeyAlgorithmTag.Cast5,
(password != null ? password.ToCharArray() : null),
hashedGen.Generate(),
unhashedGen.Generate(),
new Org.BouncyCastle.Security.SecureRandom());
// extract the keys
using (MemoryStream ms = new MemoryStream())
{
using (ArmoredOutputStream ars = new ArmoredOutputStream(ms))
{
secretKey.Encode(ars);
}
privateKey = Encoding.ASCII.GetString(ms.ToArray());
}
using (MemoryStream ms = new MemoryStream())
{
using (ArmoredOutputStream ars = new ArmoredOutputStream(ms))
{
secretKey.PublicKey.Encode(ars);
}
publicKey = Encoding.ASCII.GetString(ms.ToArray());
}
}
/// <summary>
/// Encrypt string using a PGP public key
/// </summary>
/// <param name="plain">plain text to encrypt</param>
/// <param name="armoredPublicKey">public key in ASCII "-----BEGIN PGP PUBLIC KEY BLOCK----- .. -----END PGP PUBLIC KEY BLOCK-----" format</param>
/// <returns>PGP message string</returns>
public static string PGPEncrypt(string plain, string armoredPublicKey)
{
// encode data
byte[] data = Encoding.UTF8.GetBytes(plain);
// create the WinAuth public key
PgpPublicKey publicKey = null;
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(armoredPublicKey)))
{
using (Stream dis = PgpUtilities.GetDecoderStream(ms))
{
PgpPublicKeyRingBundle bundle = new PgpPublicKeyRingBundle(dis);
foreach (PgpPublicKeyRing keyring in bundle.GetKeyRings())
{
foreach (PgpPublicKey key in keyring.GetPublicKeys())
{
if (key.IsEncryptionKey == true && key.IsRevoked() == false)
{
publicKey = key;
break;
}
}
}
}
}
// encrypt the data using PGP
using (MemoryStream encryptedStream = new MemoryStream())
{
using (ArmoredOutputStream armored = new ArmoredOutputStream(encryptedStream))
{
PgpEncryptedDataGenerator pedg = new PgpEncryptedDataGenerator(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag.Cast5, true, new Org.BouncyCastle.Security.SecureRandom());
pedg.AddMethod(publicKey);
using (Stream pedgStream = pedg.Open(armored, new byte[4096]))
{
PgpCompressedDataGenerator pcdg = new PgpCompressedDataGenerator(Org.BouncyCastle.Bcpg.CompressionAlgorithmTag.Zip);
using (Stream pcdgStream = pcdg.Open(pedgStream))
{
PgpLiteralDataGenerator pldg = new PgpLiteralDataGenerator();
using (Stream encrypter = pldg.Open(pcdgStream, PgpLiteralData.Binary, "", (long)data.Length, DateTime.Now))
{
encrypter.Write(data, 0, data.Length);
}
}
}
}
return Encoding.ASCII.GetString(encryptedStream.ToArray());
}
}
/// <summary>
/// Decrypt a PGP message (i.e. "-----BEGIN PGP MESSAGE----- ... -----END PGP MESSAGE-----")
/// using the supplied private key.
/// </summary>
/// <param name="armoredCipher">PGP message to decrypt</param>
/// <param name="armoredPrivateKey">PGP private key</param>
/// <param name="keyPassword">PGP private key password or null if none</param>
/// <returns>decrypted plain text</returns>
public static string PGPDecrypt(string armoredCipher, string armoredPrivateKey, string keyPassword)
{
// decode the private key
Dictionary<long, PgpPrivateKey> privateKeys = new Dictionary<long, PgpPrivateKey>();
using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(armoredPrivateKey)))
{
using (Stream dis = PgpUtilities.GetDecoderStream(ms))
{
PgpSecretKeyRingBundle bundle = new PgpSecretKeyRingBundle(dis);
foreach (PgpSecretKeyRing keyring in bundle.GetKeyRings())
{
foreach (PgpSecretKey key in keyring.GetSecretKeys())
{
privateKeys.Add(key.KeyId, key.ExtractPrivateKey(keyPassword != null ? keyPassword.ToCharArray() : null));
}
}
}
}
// decrypt armored block using our private key
byte[] cipher = Encoding.ASCII.GetBytes(armoredCipher);
using (MemoryStream decryptedStream = new MemoryStream())
{
using (MemoryStream inputStream = new MemoryStream(cipher))
{
using (ArmoredInputStream ais = new ArmoredInputStream(inputStream))
{
PgpObject message = new PgpObjectFactory(ais).NextPgpObject();
if (message is PgpEncryptedDataList)
{
foreach (PgpPublicKeyEncryptedData pked in ((PgpEncryptedDataList)message).GetEncryptedDataObjects())
{
message = new PgpObjectFactory(pked.GetDataStream(privateKeys[pked.KeyId])).NextPgpObject();
}
}
if (message is PgpCompressedData)
{
message = new PgpObjectFactory(((PgpCompressedData)message).GetDataStream()).NextPgpObject();
}
if (message is PgpLiteralData)
{
byte[] buffer = new byte[4096];
using (Stream stream = ((PgpLiteralData)message).GetInputStream())
{
int read;
while ((read = stream.Read(buffer, 0, 4096)) > 0)
{
decryptedStream.Write(buffer, 0, read);
}
}
}
return Encoding.UTF8.GetString(decryptedStream.ToArray());
}
}
}
}
#endregion
}
/// <summary>
/// Helper class to make a StreamWriter use an Encoding else it will default to UTF-16
/// </summary>
class EncodedStringWriter : StringWriter
{
private readonly Encoding _encoding;
public EncodedStringWriter(Encoding encoding)
{
_encoding = encoding;
}
public override Encoding Encoding
{
get
{
return _encoding;
}
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。