#region License
// CryptoManager - Logiciel de chiffrement de fichiers
// Copyright (C) 2008 G. Villard
//
// 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 2 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, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Forms;
namespace CryptoManager {
internal partial class GetSecureString : Form {
#region Constructeur
public GetSecureString() {
InitializeComponent();
}
#endregion
#region Variables
private SecureString _password = new SecureString();
private SecureString _check = new SecureString();
#endregion
#region Gestion de l'entrée clavier
private void TextboxKeyDown(object sender, KeyEventArgs e) {
TextBox tb = sender as TextBox;
if(tb == null)
return;
SecureString ss = tb == tbPass ? _password : _check;
char c = (char)e.KeyValue;
int start = tb.SelectionStart;
int len = tb.SelectionLength;
switch(e.KeyCode) {
case Keys.Back:
e.SuppressKeyPress = true;
e.Handled = true;
if(start == 0) {
return;
}
if(tb.SelectionLength > 0) {
for(int i = 0; i < len; i++)
ss.RemoveAt(start);
tb.Text = new string('*', ss.Length);
tb.SelectionStart = start;
} else {
ss.RemoveAt(--start);
tb.Text = new string('*', ss.Length);
tb.SelectionStart = start;
}
return;
case Keys.Delete:
e.SuppressKeyPress = true;
e.Handled = true;
if(start == ss.Length) {
return;
}
if(tb.SelectionLength > 0) {
for(int i = 0; i < len; i++)
ss.RemoveAt(start);
tb.Text = new string('*', ss.Length);
tb.SelectionStart = start;
} else {
ss.RemoveAt(start);
tb.Text = new string('*', ss.Length);
tb.SelectionStart = start;
}
return;
case Keys.Left:
e.SuppressKeyPress = true;
e.Handled = true;
if(start > 0)
tb.SelectionStart = --start;
return;
case Keys.Right:
e.SuppressKeyPress = true;
e.Handled = true;
if(start < tb.Text.Length)
tb.SelectionStart = ++start;
return;
case Keys.Home:
e.SuppressKeyPress = true;
e.Handled = true;
tb.SelectionStart = 0;
return;
case Keys.End:
e.SuppressKeyPress = true;
e.Handled = true;
tb.SelectionStart = tb.Text.Length;
return;
case Keys.Enter:
e.SuppressKeyPress = true;
e.Handled = true;
_password.MakeReadOnly();
_check.MakeReadOnly();
this.DialogResult = DialogResult.OK;
return;
case Keys.Escape:
e.SuppressKeyPress = true;
e.Handled = true;
_password.MakeReadOnly();
_check.MakeReadOnly();
this.DialogResult = DialogResult.Cancel;
return;
// Les touches à annuler le traitement
case Keys.Up:
case Keys.Down:
case Keys.PageDown:
case Keys.PageUp:
case Keys.Insert:
e.SuppressKeyPress = true;
e.Handled = true;
break;
default:
if(!char.IsLetterOrDigit(c) && !char.IsPunctuation(c) && !char.IsWhiteSpace(c))
return;
break;
}
if(char.IsDigit(c) || char.IsPunctuation(c) || char.IsLetter(c) || char.IsWhiteSpace(c)) {
e.SuppressKeyPress = true;
e.Handled = true;
if(char.IsLetterOrDigit(c) || char.IsPunctuation(c)) {
if(Control.IsKeyLocked(Keys.CapsLock) ^ e.Shift)
c = char.ToUpper(c);
else
c = char.ToLower(c);
}
if(tb.SelectionLength > 0) {
for(int i = 0; i < len; i++)
ss.RemoveAt(start);
}
ss.InsertAt(start, c);
tb.Text = new string('*', ss.Length);
tb.SelectionStart = start + 1;
}
}
#endregion
#region Chargement
private void Chargement(object sender, EventArgs e) {
this.TopMost = true;
this.Activate();
}
#endregion
#region Demande de password
public SecureString ShowDialog(bool withCheck) {
// On cache le champ de vérificatino si nécessaire
if(!withCheck) {
tbVerif.Hide();
tbValider.Top -= 26;
tbCancel.Top -= 26;
this.Height -= 8;
}
if(base.ShowDialog() != DialogResult.OK)
return null;
if(_password.Length == 0) {
MessageBox.Show("pwdempty".GetResString(), "err".GetResString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
// Si on demande une vérification de password, il faut faire les tests
if(withCheck) {
if(_password.Length != _check.Length) {
MessageBox.Show("pwdcheckfail".GetResString(), "err".GetResString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
byte[] pass = new byte[_password.Length], check = new byte[_check.Length];
IntPtr p1 = IntPtr.Zero, p2 = IntPtr.Zero;
bool rst = true;
try {
p1 = Marshal.SecureStringToBSTR(_password);
p2 = Marshal.SecureStringToBSTR(_check);
Marshal.Copy(p1, pass, 0, _password.Length);
Marshal.Copy(p2, check, 0, _check.Length);
for(int i = 0; i < _password.Length; i++) {
if(pass[i] != check[i])
rst = false;
}
} catch(Exception ex) {
MessageBox.Show(ex.Message);
MessageBox.Show(ex.StackTrace);
}
finally {
if(p1 != IntPtr.Zero)
Marshal.ZeroFreeBSTR(p1);
if(p2 != IntPtr.Zero)
Marshal.ZeroFreeBSTR(p2);
if(pass != null)
pass.FillWithZero();
if(check != null)
check.FillWithZero();
}
if(!rst) {
MessageBox.Show("pwdcheckfail".GetResString(), "err".GetResString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
return _password.Copy();
}
public static SecureString Demand(bool withCheck = true) {
GetSecureString gss = new GetSecureString();
SecureString rst = gss.ShowDialog(withCheck);
gss.Dispose();
return rst;
}
#endregion
#region Bouttons de validation/annulation
private void Valider(object sender, EventArgs e) {
_password.MakeReadOnly();
_check.MakeReadOnly();
this.DialogResult = DialogResult.OK;
}
private void Annuler(object sender, EventArgs e) {
_password.MakeReadOnly();
_check.MakeReadOnly();
this.DialogResult = DialogResult.Cancel;
}
#endregion
}
}