Encryption (TripleDES) between Universal App and ASP.Net Web Service - asp.net

I am totally lost. I build a Universal App (VB.net) which is consuming a web service on my (Azure Website Vb.net).
My Universal APP (UA) is sending userdata (Username an EmployeeNR) to a webservice and the Webservice is checking that data.
With TripleDES I encrypted the EmployeeNr and Username in the Universal and send it to the WebService. Now i am struggling how to decrypt the TripleDES on my WebService.
In the Universal App I work with Windows.Security.Cryptography which is not available on the Webservice site (asp.net).
I can only use System.Security.Cryptography.
I can encrypt and decrypt on Windows App site.
I also can encrpyt and decrypt on the Web Service site.
But if I pass an encrypted String form Win App to Web Service. Decryption is not working.
Problem is: On both sides, I use the same STRING, same Key and TripleDES encryption, but the result is different.
MY Encryption side - Windows Universal APP
Function myencrptor(ByVal Plaintext As String, ByVal mykey As String) As String
Dim crypt As SymmetricKeyAlgorithmProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.TripleDesCbcPkcs7)
Dim PlainTextbuffer As IBuffer = CryptographicBuffer.ConvertStringToBinary(Plaintext, BinaryStringEncoding.Utf8)
Dim mykeybuffer As IBuffer = CryptographicBuffer.ConvertStringToBinary(mykey, BinaryStringEncoding.Utf8)
Dim magickey As CryptographicKey = crypt.CreateSymmetricKey(mykeybuffer)
Dim signed As IBuffer = CryptographicEngine.Encrypt(magickey, PlainTextbuffer, Nothing)
Dim verschlüsselt As String = CryptographicBuffer.EncodeToBase64String(signed)
Return verschlüsselt
End Function
My Server Side
Partial Class regal_appsync_Default
Inherits System.Web.UI.Page
Public NotInheritable Class Simple3Des
Private xTripleDES As New TripleDESCryptoServiceProvider
Sub New(ByVal key As String)
' Initialize the crypto provider.
xTripleDES.Key = TruncateHash(key, xTripleDES.KeySize \ 8)
xTripleDES.IV = TruncateHash("", xTripleDES.BlockSize \ 8)
End Sub
Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
Public Function EncryptData(ByVal plaintext As String) As String
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
xTripleDES.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
End Function
Public Function DecryptData(ByVal encryptedtext As String) As String
' Convert the encrypted text string to a byte array.
Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim decStream As New CryptoStream(ms, xTripleDES.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
decStream.FlushFinalBlock()
' Convert the plaintext stream to a string.
Return System.Text.Encoding.UTF8.GetString(ms.ToArray)
End Function
End Class
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Lbl1.Text = myEncoding(Txt1.Text)
End Sub
Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Lbl1.Text = myDecoding(Lbl1.Text)
End Sub
Function myEncoding(ByVal plainText As String) As String
Dim wrapper As New Simple3Des("012345678901234567891234")
Dim cipherText As String = wrapper.EncryptData(plainText)
Return cipherText
End Function
Function myDecoding(ByVal cipherText As String) As String
' DecryptData throws if the wrong password is used.
Dim wrapper As New Simple3Des("012345678901234567891234")
Try
Dim plainText As String = wrapper.DecryptData(cipherText)
Return plainText
Catch ex As System.Security.Cryptography.CryptographicException
Return "problem"
End Try
End Function
End Class
looking forward to any helpful tips!
best wishes
hendrik

Related

QueryStringModule with FriendlyUrls does not working

Good morning, I need to encrypt my querystring and i found an interesting method in this link and I convert it in vb.net:
Imports System
Imports System.IO
Imports System.Web
Imports System.Text
Imports System.Security.Cryptography
Public Class QueryStringModule
Implements IHttpModule
Public Sub Dispose() Implements IHttpModule.Dispose
End Sub
Public Sub Init(ByVal context As HttpApplication) Implements IHttpModule.Init
AddHandler context.BeginRequest, New EventHandler(AddressOf context_BeginRequest)
End Sub
Private Const PARAMETER_NAME As String = "enc="
Private Const ENCRYPTION_KEY As String = "key"
Private Sub context_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim context As HttpContext = HttpContext.Current
If context.Request.Url.OriginalString.Contains("aspx") AndAlso context.Request.RawUrl.Contains("?") Then
Dim query As String = ExtractQuery(context.Request.RawUrl)
Dim path As String = GetVirtualPath()
If query.StartsWith(PARAMETER_NAME, StringComparison.OrdinalIgnoreCase) Then
Dim rawQuery As String = query.Replace(PARAMETER_NAME, String.Empty)
Dim decryptedQuery As String = Decrypt(rawQuery)
context.RewritePath(path, String.Empty, decryptedQuery)
ElseIf context.Request.HttpMethod = "GET" Then
Dim encryptedQuery As String = Encrypt(query)
context.Response.Redirect(path & encryptedQuery)
End If
End If
End Sub
Private Shared Function GetVirtualPath() As String
Dim path As String = HttpContext.Current.Request.RawUrl
path = path.Substring(0, path.IndexOf("?"))
path = path.Substring(path.LastIndexOf("/") + 1)
Return path
End Function
Private Shared Function ExtractQuery(ByVal url As String) As String
Dim index As Integer = url.IndexOf("?") + 1
Return url.Substring(index)
End Function
Private ReadOnly Shared SALT As Byte() = Encoding.ASCII.GetBytes(ENCRYPTION_KEY.Length.ToString())
Public Shared Function Encrypt(ByVal inputText As String) As String
Dim rijndaelCipher As RijndaelManaged = New RijndaelManaged()
Dim plainText As Byte() = Encoding.Unicode.GetBytes(inputText)
Dim SecretKey As PasswordDeriveBytes = New PasswordDeriveBytes(ENCRYPTION_KEY, SALT)
Using encryptor As ICryptoTransform = rijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16))
Using memoryStream As MemoryStream = New MemoryStream()
Using cryptoStream As CryptoStream = New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
cryptoStream.Write(plainText, 0, plainText.Length)
cryptoStream.FlushFinalBlock()
Return "?" & PARAMETER_NAME & Convert.ToBase64String(memoryStream.ToArray())
End Using
End Using
End Using
End Function
Public Shared Function Decrypt(ByVal inputText As String) As String
Dim rijndaelCipher As RijndaelManaged = New RijndaelManaged()
Dim encryptedData As Byte() = Convert.FromBase64String(inputText)
Dim secretKey As PasswordDeriveBytes = New PasswordDeriveBytes(ENCRYPTION_KEY, SALT)
Using decryptor As ICryptoTransform = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16))
Using memoryStream As MemoryStream = New MemoryStream(encryptedData)
Using cryptoStream As CryptoStream = New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
Dim plainText As Byte() = New Byte(encryptedData.Length - 1) {}
Dim decryptedCount As Integer = cryptoStream.Read(plainText, 0, plainText.Length)
Return Encoding.Unicode.GetString(plainText, 0, decryptedCount)
End Using
End Using
End Using
End Function
End Class
but also my project use FriendlyUrls and I figured out that with FriendlyUrls the things does not working and always return the url without the extension ".aspx" but with the querystring not encrypted
Imports System.Web.Routing
Imports Microsoft.AspNet.FriendlyUrls
Public Module RouteConfig
Sub RegisterRoutes(ByVal routes As RouteCollection)
Dim settings As FriendlyUrlSettings = New FriendlyUrlSettings() With {
.AutoRedirectMode = RedirectMode.Permanent
}
routes.EnableFriendlyUrls(settings)
End Sub
End Module
of course if I set .AutoRedirectMode to Off it works but without friendlyurls.
Am I doing something wrong?
EDIT 09/10/2019:
We figured out that remove the test of OriginalString.Contains("aspx") in the context_BeginRequest the encryption works, now the code is like:
Private Sub context_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim context As HttpContext = HttpContext.Current
If context.Request.RawUrl.Contains("?") Then
Dim query As String = ExtractQuery(context.Request.RawUrl)
Dim path As String = GetVirtualPath()
If query.StartsWith(PARAMETER_NAME, StringComparison.OrdinalIgnoreCase) Then
Dim rawQuery As String = query.Replace(PARAMETER_NAME, String.Empty)
Dim decryptedQuery As String = Decrypt(rawQuery)
context.RewritePath(path, String.Empty, decryptedQuery)
ElseIf context.Request.HttpMethod = "GET" Then
Dim encryptedQuery As String = Encrypt(query)
context.Response.Redirect(path & encryptedQuery)
End If
End If
End Sub
But now the question is: there is other method to target an aspx page without test the extension? I think there is a risk that targeting things that not should target like "ashx" or cache-busting code that use querystring.

Get each key value out of a dictionary of strings object without using newsoft json

I have an indexpage.aspx which I post data into on page load. In this page I created list of strings
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim openWith As New SortedList(Of String, String)
' Add some elements to the list. There are no
' duplicate keys, but some of the values are duplicates.
openWith.Add("version", "1")
openWith.Add("key", ConfigurationManager.AppSettings("publickey"))
openWith.Add("cmd", "get_callback_address")
openWith.Add("currency", "coin")
Call POSTAPI("get_callback_address", openWith)
End Sub
Now I have a payment class which has postapi function, here's the class
Public Shared Function POSTAPI(cmd As String, Optional parms As SortedList(Of String, String) = Nothing) As Dictionary(Of String, Object)
Dim post_data As String = ""
For Each parm As KeyValuePair(Of String, String) In parms
If post_data.Length > 0 Then
post_data += "&"
End If
post_data += parm.Key + "=" + Uri.EscapeDataString(parm.Value)
Next
Dim keyBytes As Byte() = encoding.GetBytes(s_privkey)
Dim postBytes As Byte() = encoding.GetBytes(post_data)
Dim hmacsha512 = New System.Security.Cryptography.HMACSHA512(keyBytes)
Dim hmac As String = BitConverter.ToString(hmacsha512.ComputeHash(postBytes)).Replace("-", String.Empty)
' do the post:
Dim cl As New System.Net.WebClient()
cl.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
cl.Headers.Add("HMAC", hmac)
cl.Encoding = encoding
Dim ret = New Dictionary(Of String, Object)()
Try
Dim resp As String = cl.UploadString("https://www.coinpayments.net/api.php", post_data)
Dim decoder = New System.Web.Script.Serialization.JavaScriptSerializer()
ret = decoder.Deserialize(Of Dictionary(Of String, Object))(resp)
Catch e As System.Net.WebException
ret("error") = "Exception while contacting CoinPayments.net: " + e.Message
Catch e As Exception
ret("error") = "Unknown exception: " + e.Message
End Try
Return ret
End Function
Its posting successfully but A successful call to the 'get_callback_address' or 'get_deposit_address' command will give you a result similar to this (JSON):
{
"error":"ok",
"result":{
"address":"1BitcoinAddress",
"pubkey":"",
"dest_tag":100,
}
}
Above are the keys and values is returning. Now my question is I only want to get the values of result and split it so it gives me "1BitcoinAddress", "pubkey" and save it to my database(I want to get the 3 values of that resultkey so i can save it in my database".
Thank you.
Since you deserialized the incoming json as a Dictionary(Of String, Object) the JavaScriptSerializer should have already created a second dictionary for the value of the result key. The only thing you have to do now, is create a variable that takes the value stored in the dictionary and cast it as a Dictionary(Of String, Object) in order to use it, like in this example
Dim json As String = "{" +
"""error"":""ok""," +
"""result"":{" +
"""address"":""1BitcoinAddress""," +
"""pubkey"":""""," +
"""dest_tag"":100" +
"}" +
"}"
Dim deserializer = New System.Web.Script.Serialization.JavaScriptSerializer()
'get the full dictionary
Dim dictionary = deserializer.Deserialize(Of Dictionary(Of String, Object))(json)
' make sure there is a key in your dictionary
If dictionary.ContainsKey("result") Then
'cast the value for "result" as a dictionary
Dim resultDictionary As Dictionary(Of String, Object) = _
DirectCast(dictionary("result"), Dictionary(Of String, Object))
'you can then access the keys by their key
Console.WriteLine("address: {0}, pubkey: {1}, dest_tag: {2}", _
resultDictionary("address"), _
resultDictionary("pubkey"), _
resultDictionary("dest_tag"))
End If
With your input, the program gives an output on the console, like this:
address: 1BitcoinAddress, pubkey: , dest_tag: 100
The big question of your question is really why you want to solve the deserialization without the use of Json.net. On the website for the JavaScriptSerializer,
it says at once:
Json.NET should be used serialization and deserialization. Provides serialization and deserialization functionality for AJAX-enabled applications.

AppPool identity instead of Current User only when Impersonating from Class Library (dll)

We have a class library of some common methods we use throughout multiple web apps and we are having an issue with our Impersonation class. When using impersonation with LogonUser in each individual application, Environment.UserName returns the user who is using the application. But when we call it within our class library's impersonation using block, it returns as the AppPool identity.
Returns username of client:
Declare Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer
If (LogonUser(Config.AdminUser, Config.AdminDomain, Config.AdminPassword, 9, 0, token) <> 0) Then
Dim newIdentity As WindowsIdentity = New WindowsIdentity(token)
Using impersonatedUser As WindowsImpersonationContext = newIdentity.Impersonate()
name = Environment.UserName
End Using
End If
Returns app pool username:
Imports Class.Library
Using admin As New Impersonation
name = Environment.UserName
End Using
HttpContext.Current.User.Identity.Name seems to return the username we are looking for but we cannot see why Environment.UserName works effectively when on the server, but only when it doesn't use our custom class library's dll reference. Here is a look at our impersonation class:
Public Class Impersonation : Implements IDisposable
Private impersonationContext As WindowsImpersonationContext = Nothing
Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer
Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Boolean
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal hToken As IntPtr, ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
Private Shared newIdentity As WindowsIdentity
Private Shared token As New IntPtr(0)
Public Sub New(Optional ByVal userName As String = "", Optional ByVal password As String = "", Optional ByVal domainName As String = Config.AdminDomain)
If userName = "" Then
userName = Config.AdminUser
End If
If password = "" Then
password = Config.AdminPassword
End If
Dim logonType As Integer = 9
impersonationContext = ImpersonateUser(userName, domainName, password, logonType)
End Sub
Private Sub Undo()
If impersonationContext IsNot Nothing Then
impersonationContext.Undo()
End If
End Sub
Private Shared Function ImpersonateUser(ByVal userName As String, ByVal domain As String, ByVal password As String, ByVal logonType As Integer) As WindowsImpersonationContext
Dim res As WindowsImpersonationContext = Nothing
Dim tempWindowsIdentity As WindowsIdentity = Nothing
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
Try
If (RevertToSelf()) Then
If LogonUser(userName, domain, password, logonType, 0, token) Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
Return tempWindowsIdentity.Impersonate()
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Finally
If token <> IntPtr.Zero Then
CloseHandle(token)
End If
If tokenDuplicate <> IntPtr.Zero Then
CloseHandle(tokenDuplicate)
End If
End Try
Return res
End Function
Private disposedValue As Boolean = False
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
Undo()
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
I have a feeling that it has something to do with the dll file being on the server and when we use the using block, Environment.UserName gets the username from where the process is running on the server. But I can't see why it would work initially when creating a New WindowsIdentity() within the method that uses the impersonation not when we reference it from our dll since they are both running on the server.
Essentially, HttpContext.Current.User.Identity.Name has become an issue for us when we are running things locally and trying to debug issues that arise. We would like, 1. an answer to why this is happening for knowledge purposes and 2. a possible resolution if their even is any beyond HttpContext.Current.User.Identity.Name. (answers in VB or C# are welcomed.)
I resolved my issue by creating a new method in my class library:
Public Shared Function Current() As String
If Not HttpContext.Current.Request.IsLocal Then
Dim id As String = HttpContext.Current.User.Identity.Name
Return id.Substring(4)
Else
Return Environment.UserName
End If
End Function
If the code is run on the server, it uses HttpContext to pull the domain\username. Then I substringed out the domain (our domain is only three chars).
If it is run locally, I return Environment.UserName
I call this string within my web app by simply referencing the class and method (Employees.Current)

Active Directory - check if password never expires?

Is there a way in Visual Basic to check if the user's password is set to never expire in Active Directory?
I've found a way to find the last date it was changed, but I can't find the other available options.
Dim de As DirectoryServices.DirectoryEntry = GetUser(uDetails.username)
Dim objUser = GetObject(de.Path)
If objUser.PasswordLastChanged < DateTime.Now.AddMonths(-3) Then
...
Where can I find a list of all available objUser properties?
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// one of the properties exposed is "PasswordNeverExpires" (bool)
if(user.PasswordNeverExpires)
{
// do something here....
...
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
For .NET 2.0 you can use some LDAP. The magic part is userAccountControl:1.2.840.113556.1.4.803:=65536. The first part is the property that you want to search, the second means "bitwise AND" and the third is the bitwise flag to check, in this case the 17th bit. You can see more on the bitwise AND and OR in Active Directory in How to query Active Directory by using a bitwise filter.
In the code below update the SearchRoot variable with your domain controller (DC) and FQDN.
Imports System.DirectoryServices
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
''//Bind to the root of our domain
''// YOU_DOMAIN_CONTROLLER should be one of your DCs
''// EXAMPLE and COM are the parts of your FQDN
Dim SearchRoot As DirectoryEntry = New DirectoryEntry("LDAP://YOUR_DOMAIN_CONTROLLER/dc=EXAMPLE,dc=COM")
''//Create a searcher bound to the root
Dim Searcher As DirectorySearcher = New DirectorySearcher(SearchRoot)
''//Set our filer. The last part is dumb but that is the way that LDAP was built.
''//It basically does a bitwise AND looking for the 17th bit to be set on that property "userAccountControl" which is the "password never expires" bit
''//See this if you care to learn more http://support.microsoft.com/kb/269181
Searcher.Filter = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"
''//Find all of the results
Dim Results = Searcher.FindAll()
Dim DE As DirectoryEntry
''//Loop through each result
For Each R As SearchResult In Results
''//Get the result as a DirectoryEntry object
DE = R.GetDirectoryEntry()
''//Output the object name
Console.WriteLine(DE.Name)
Next
End Sub
End Class
public bool isPasswordExpired(String p_UserName, String p_DomainName)
{
bool m_Check=false;
int m_Val1 = (int)de1.Properties["userAccountControl"].Value;
int m_Val2 = (int) 0x10000;
if (Convert.ToBoolean(m_Val1 & m_Val2))
{
m_Check = true;
} //end
return m_Check
}
You could use the following code originally from here that I've translated from C# and modified a little bit according to your question (added a getter):
Dim pwdNeverExpires = getPasswordNeverExpires("Tim")
setPasswordNeverExpires("Tim", True)
' See http://msdn.microsoft.com/en-us/library/aa772300(VS.85).aspx
<Flags()> _
Private Enum ADS_USER_FLAG_ENUM
ADS_UF_SCRIPT = 1
' 0x1
ADS_UF_ACCOUNTDISABLE = 2
' 0x2
ADS_UF_HOMEDIR_REQUIRED = 8
' 0x8
ADS_UF_LOCKOUT = 16
' 0x10
ADS_UF_PASSWD_NOTREQD = 32
' 0x20
ADS_UF_PASSWD_CANT_CHANGE = 64
' 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128
' 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256
' 0x100
ADS_UF_NORMAL_ACCOUNT = 512
' 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048
' 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096
' 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 8192
' 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 65536
' 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 131072
' 0x20000
ADS_UF_SMARTCARD_REQUIRED = 262144
' 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 524288
' 0x80000
ADS_UF_NOT_DELEGATED = 1048576
' 0x100000
ADS_UF_USE_DES_KEY_ONLY = 2097152
' 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 4194304
' 0x400000
ADS_UF_PASSWORD_EXPIRED = 8388608
' 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216
' 0x1000000
End Enum
Protected Overridable Function getPasswordNeverExpires(ByVal userName As String) As Boolean
Const userNameString As String = "userName"
Const userFlagsString As String = "userFlags"
Dim machineName As String = Environment.MachineName
Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
If userInThisComputerDirectoryEntry Is Nothing Then
Throw New ArgumentException("not found in " & machineName, userNameString)
End If
Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
Return userFlags = (userFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End Function
Protected Overridable Sub setPasswordNeverExpires(ByVal userName As String, ByVal passwordNeverExpires As Boolean)
Const userNameString As String = "userName"
Const userFlagsString As String = "userFlags"
Dim machineName As String = Environment.MachineName
Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
If userInThisComputerDirectoryEntry Is Nothing Then
Throw New ArgumentException("not found in " & machineName, userNameString)
End If
Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
Dim newUserFlags As ADS_USER_FLAG_ENUM = userFlags
If passwordNeverExpires Then
newUserFlags = newUserFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD
Else
newUserFlags = newUserFlags And (Not ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End If
userFlagsProperties.Value = newUserFlags
userInThisComputerDirectoryEntry.CommitChanges()
End Sub
Protected Overridable Function getUserInThisComputerDirectoryEntry(ByVal machineName As String, ByVal userName As String) As DirectoryEntry
Dim computerDirectoryEntry As DirectoryEntry = getComputerDirectoryEntry(machineName)
Const userSchemaClassName As String = "user"
Return computerDirectoryEntry.Children.Find(userName, userSchemaClassName)
End Function
Protected Overridable Function getComputerDirectoryEntry(ByVal machineName As String) As DirectoryEntry
'Initiate DirectoryEntry Class To Connect Through WINNT Protocol
' see: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path.aspx
Const pathUsingWinNTComputerMask As String = "WinNT://{0},computer"
Dim path As String = String.Format(pathUsingWinNTComputerMask, machineName)
Dim thisComputerDirectoryEntry As New DirectoryEntry(path)
Return thisComputerDirectoryEntry
End Function
You have to add a reference to System.DirectoryServices. I have tested it on Windows Server 2008 with .NET Framework 4 (it should also work under 2.0) without Active Directory. But check it out yourself and feel free to extend it to get/set other properties as well or connect to other machines (SomeDomain/OtherComputerName instead of Environment.MachineName).

CA2000: Object is not disposed along all exception paths

I am having trouble trying to figure out why I'm getting this warning in following code.
CA2000 : Microsoft.Reliability : In method 'Encryption64.Decrypt(String, String)', object 'des' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'des' before all references to it are out of scope.
CA2000 : Microsoft.Reliability : In method 'Encryption64.Encrypt(String, String)', object 'des' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'des' before all references to it are out of scope.
Public Class Encryption64
Private key() As Byte = {}
Private IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
Public Function Decrypt(ByVal stringToDecrypt As String, ByVal sEncryptionKey As String) As String
Dim des As New DESCryptoServiceProvider()
Dim ms As New MemoryStream()
Dim ReturnValue As String = String.Empty
Try
Dim inputByteArray(stringToDecrypt.Length) As Byte
key = System.Text.Encoding.UTF8.GetBytes(Left(sEncryptionKey, 8))
inputByteArray = Convert.FromBase64String(stringToDecrypt)
Dim cs As New CryptoStream(ms, des.CreateDecryptor(key, IV),CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
ReturnValue = encoding.GetString(ms.ToArray())
Catch e As Exception
ReturnValue = e.Message
Finally
If des IsNot Nothing Then
des.Dispose()
End If
If ms IsNot Nothing Then
ms.Dispose()
End If
End Try
Return ReturnValue
End Function
Public Function Encrypt(ByVal stringToEncrypt As String, ByVal SEncryptionKey As String) As String
Dim des As New DESCryptoServiceProvider()
Dim ms As New MemoryStream()
Dim ReturnValue As String = String.Empty
Try
key = System.Text.Encoding.UTF8.GetBytes(Left(SEncryptionKey, 8))
Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)
Dim cs As New CryptoStream(ms, des.CreateEncryptor(key, IV), CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
ReturnValue = Convert.ToBase64String(ms.ToArray())
Catch e As Exception
ReturnValue = e.Message
Finally
If des IsNot Nothing Then
des.Dispose()
End If
If ms IsNot Nothing Then
ms.Dispose()
End If
End Try
Return ReturnValue
End Function
End Class
Since you are declaring (and instantiating) your des objects outside of the Try ... Finally blocks, it is possible for your code to raise an exception in the line Dim ms As New MemoryStream() and your .Dispose() will not be called.
When you are working with objects that implement IDisposable, it is much preferable where possible to wrap them in a Using block instead of a Try...Finally block. For example:
Public Function Decrypt(ByVal stringToDecrypt As String, ByVal sEncryptionKey As String) As String
Dim ms As New MemoryStream()
Dim ReturnValue As String = String.Empty
Dim inputByteArray(stringToDecrypt.Length) As Byte
key = System.Text.Encoding.UTF8.GetBytes(Left(sEncryptionKey, 8))
inputByteArray = Convert.FromBase64String(stringToDecrypt)
Using ms as New MemoryStream
Using des As New DESCryptoServiceProvider
Dim cs As New CryptoStream(ms, des.CreateDecryptor(key, IV),CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
End Using ' des
Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
ReturnValue = encoding.GetString(ms.ToArray())
End Using ' ms
Catch e As Exception
ReturnValue = e.Message
End Try
Return ReturnValue
End Function
Just a guess, but maybe it's not smart enough to realize that this code line will always be true:
If des IsNot Nothing Then
In other words, it might assume that because there is a conditional statement, the Dispose() call might not be executed.
To check, you can try commenting out the "if" and see if the warning goes away.

Resources