(Cross post from framework.aspne t.security)
Hi. I testing some asp.net code that generates a 256 bit Aes Symmetric Key
and a 256 bit entropy value.
I encrypt the Aes key(without storing it as Base64) with the host's dpapi
using the entropy value(without storing it as Base64),
and then store the encrypted Aes key value and the entropy value in some
SHARED VARIABLES AS BYTE ARRAYS(not Base64).
I then decrypt the stored encrypted Aes value with the dpapi using the
stored entropy value.
I am declaring the default padding when generating the key as:
aesProvider.Pad ding = PaddingMode.PKC S7
After the encryption, for my comparison purposes, I display the unencrypted
Aes key as a Base 64 value. Since 32 bytes is a multiple
of three, one would not expect any BASE64 padding characters in the
displayed value, yet I always get a value that ends in the Base64
padding symbol of '=' which means a base64 padded group of 3 zeroes.
When I decrypt the encrypted Aes key value, and convert it to Base64 for
display, it always shows up as having the last character
being an 'A' which is the base64 value for '0' or 'zero'
I first suspected that the PKCS7 mode is causing my problems, but reading
the PKCS7 help implies that the padding is used in the cipher blocks,
not in the key generation. For convenience, I used the
RijndaelManaged .GenerateKey() function to generate the key, BUT perhaps I
might as well
as used the RNGCryptoServic eProvider.GetBy tes() to do this. Indeed, I used
the RNGCryptoServic eProvider.GetBy tes() to generate a 32 byte entropy
value,
yet when I convert it to base64 for viewing, it has an '=' as the last
character, meaning that it too is incorrectly being padded.
Below is a summary of what I get during the generate and encryption:
Generate and Encrypt:
Generated Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6Ns=
Generated Aes Base64 Encoded String Symmetric Key Encrypted with Dpapi:
AQAAANCMnd8BFdE RjHoAwE/Cl+sBAAAAYfcANK BCn0WrzhCNlOn8S wQAAAACAAAAAAAD ZgAAqAAAABAAAAB Vt1GQd/7tXNI/sKRdwGmzAAAAAAS AAACgAAAAEAAAAE zxv5pzWw2v2H4cS VVoK2woAAAAMc60 9Ix8n4QMFy44PHR sInDD44lvwZPL04 uZg19szbnPJskt4 gA5LhQAAABvMuTk meSa2dv3BkXdJA4 eHQxgGwA=
Using Entropy
Generated Entropy As Base64 Encoded String:
WCXGLrtx1SN81b5 e8aI11ntBvjRR11 UmwSiqj2+9vaA=
After Decryption, I get:
Decrypt and Compare:
Generated Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6Ns=
Dpapi Decrypted Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6NsA
The code behind is as follows (Sorry I could not color code the code):
Imports System.Security .Cryptography
Public Class EncryptDecryptW ithDpapiBase64E ncodedStrings
Inherits System.Web.UI.P age
'Public Shared entropyValueAsB yte() As Byte
'Public Shared dpapiEncryptedA esKeyAsByte() As Byte
'Have to have shared variables because new page is emitted
'on postback with new instance of page
Private Shared _entropyValueAs Byte(31) As Byte
Protected WithEvents generatedB64Aes Key As
System.Web.UI.W ebControls.Text Box
Private Shared _dpapiEncrypted AesKeyAsByte() As Byte
Public Shared Property entropyValueAsB yte() As Byte()
Get
Return _entropyValueAs Byte
End Get
Set(ByVal Value As Byte())
_entropyValueAs Byte = Value
End Set
End Property
Public Shared Property dpapiEncryptedA esKeyAsByte() As Byte()
Get
Return _dpapiEncrypted AesKeyAsByte
End Get
Set(ByVal Value As Byte())
_dpapiEncrypted AesKeyAsByte = Value
End Set
End Property
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnos tics.DebuggerSt epThrough()> Private Sub
InitializeCompo nent()
End Sub
Protected WithEvents cleartextTextBo x As
System.Web.UI.W ebControls.Text Box
Protected WithEvents ciphertextTextB ox As
System.Web.UI.W ebControls.Text Box
Protected WithEvents entropyCheckBox As
System.Web.UI.W ebControls.Chec kBox
Protected WithEvents encryptButton As System.Web.UI.W ebControls.Butt on
Protected WithEvents decryptButton As System.Web.UI.W ebControls.Butt on
Protected WithEvents generatedEntrop yTextBox As
System.Web.UI.W ebControls.Text Box
'NOTE: The following placeholder declaration is required by the Web Form
Designer.
'Do not delete or move it.
Private designerPlaceho lderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArg s) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeCompo nent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArg s) Handles MyBase.Load
'Put user code to initialize the page here
End Sub
Public Enum Store
USE_MACHINE_STO RE
USE_USER_STORE
End Enum
Friend Function CreateKey() As Byte()
'Create a new AES Service Provider
Dim aesProvider As New RijndaelManaged
'Declare the key size
aesProvider.Key Size = 256
aesProvider.Blo ckSize = 256
aesProvider.Pad ding = PaddingMode.PKC S7
aesProvider.Gen erateKey()
Return aesProvider.Key
End Function
Friend Function CreateEntropyVa lue() As Byte()
Dim rng As New RNGCryptoServic eProvider
Dim rng256EntropyBy teValue(31) As Byte
rng.GetBytes(rn g256EntropyByte Value)
Return rng256EntropyBy teValue
End Function
Private Sub encryptButton_C lick(ByVal sender As System.Object, ByVal e
As System.EventArg s) Handles encryptButton.C lick
Dim dp As New RindjaelTest.Mi crosoft.Win32.D PAPI.DataProtec tor
Dim AesKeyValueInBy tes(31) As Byte
AesKeyValueInBy tes = CreateKey()
generatedB64Aes Key.Text = Convert.ToBase6 4String(AesKeyV alueInBytes)
If entropyCheckBox .Checked Then
entropyValueAsB yte = CreateEntropyVa lue()
dpapiEncryptedA esKeyAsByte = dp.Encrypt(AesK eyValueInBytes,
entropyValueAsB yte, Store.USE_MACHI NE_STORE)
ciphertextTextB ox.Text =
Convert.ToBase6 4String(dpapiEn cryptedAesKeyAs Byte)
generatedEntrop yTextBox.Text =
Convert.ToBase6 4String(entropy ValueAsByte)
Else
dpapiEncryptedA esKeyAsByte = dp.Encrypt(AesK eyValueInBytes,
Nothing, Store.USE_MACHI NE_STORE)
ciphertextTextB ox.Text =
Convert.ToBase6 4String(dpapiEn cryptedAesKeyAs Byte)
End If
ciphertextTextB ox.Text.TrimEnd ()
End Sub
Private Sub decryptButton_C lick(ByVal sender As System.Object, ByVal e
As System.EventArg s) Handles decryptButton.C lick
If Not dpapiEncryptedA esKeyAsByte Is Nothing Then
Dim dp As New RindjaelTest.Mi crosoft.Win32.D PAPI.DataProtec tor
If entropyCheckBox .Checked Then
cleartextTextBo x.Text =
Convert.ToBase6 4String(dp.Decr ypt(dpapiEncryp tedAesKeyAsByte ,
entropyValueAsB yte, Store.USE_MACHI NE_STORE))
Else
cleartextTextBo x.Text =
Convert.ToBase6 4String(dp.Decr ypt(dpapiEncryp tedAesKeyAsByte , Nothing,
Store.USE_MACHI NE_STORE))
End If
cleartextTextBo x.Text.TrimEnd( )
End If
End Sub
End Class
Hi. I testing some asp.net code that generates a 256 bit Aes Symmetric Key
and a 256 bit entropy value.
I encrypt the Aes key(without storing it as Base64) with the host's dpapi
using the entropy value(without storing it as Base64),
and then store the encrypted Aes key value and the entropy value in some
SHARED VARIABLES AS BYTE ARRAYS(not Base64).
I then decrypt the stored encrypted Aes value with the dpapi using the
stored entropy value.
I am declaring the default padding when generating the key as:
aesProvider.Pad ding = PaddingMode.PKC S7
After the encryption, for my comparison purposes, I display the unencrypted
Aes key as a Base 64 value. Since 32 bytes is a multiple
of three, one would not expect any BASE64 padding characters in the
displayed value, yet I always get a value that ends in the Base64
padding symbol of '=' which means a base64 padded group of 3 zeroes.
When I decrypt the encrypted Aes key value, and convert it to Base64 for
display, it always shows up as having the last character
being an 'A' which is the base64 value for '0' or 'zero'
I first suspected that the PKCS7 mode is causing my problems, but reading
the PKCS7 help implies that the padding is used in the cipher blocks,
not in the key generation. For convenience, I used the
RijndaelManaged .GenerateKey() function to generate the key, BUT perhaps I
might as well
as used the RNGCryptoServic eProvider.GetBy tes() to do this. Indeed, I used
the RNGCryptoServic eProvider.GetBy tes() to generate a 32 byte entropy
value,
yet when I convert it to base64 for viewing, it has an '=' as the last
character, meaning that it too is incorrectly being padded.
Below is a summary of what I get during the generate and encryption:
Generate and Encrypt:
Generated Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6Ns=
Generated Aes Base64 Encoded String Symmetric Key Encrypted with Dpapi:
AQAAANCMnd8BFdE RjHoAwE/Cl+sBAAAAYfcANK BCn0WrzhCNlOn8S wQAAAACAAAAAAAD ZgAAqAAAABAAAAB Vt1GQd/7tXNI/sKRdwGmzAAAAAAS AAACgAAAAEAAAAE zxv5pzWw2v2H4cS VVoK2woAAAAMc60 9Ix8n4QMFy44PHR sInDD44lvwZPL04 uZg19szbnPJskt4 gA5LhQAAABvMuTk meSa2dv3BkXdJA4 eHQxgGwA=
Using Entropy
Generated Entropy As Base64 Encoded String:
WCXGLrtx1SN81b5 e8aI11ntBvjRR11 UmwSiqj2+9vaA=
After Decryption, I get:
Decrypt and Compare:
Generated Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6Ns=
Dpapi Decrypted Aes Base64 Encoded String Symmetric Key:
wzHp7M3tRpXiWw4 SWkMzEmorBHTNEj ENDgSeGi8B6NsA
The code behind is as follows (Sorry I could not color code the code):
Imports System.Security .Cryptography
Public Class EncryptDecryptW ithDpapiBase64E ncodedStrings
Inherits System.Web.UI.P age
'Public Shared entropyValueAsB yte() As Byte
'Public Shared dpapiEncryptedA esKeyAsByte() As Byte
'Have to have shared variables because new page is emitted
'on postback with new instance of page
Private Shared _entropyValueAs Byte(31) As Byte
Protected WithEvents generatedB64Aes Key As
System.Web.UI.W ebControls.Text Box
Private Shared _dpapiEncrypted AesKeyAsByte() As Byte
Public Shared Property entropyValueAsB yte() As Byte()
Get
Return _entropyValueAs Byte
End Get
Set(ByVal Value As Byte())
_entropyValueAs Byte = Value
End Set
End Property
Public Shared Property dpapiEncryptedA esKeyAsByte() As Byte()
Get
Return _dpapiEncrypted AesKeyAsByte
End Get
Set(ByVal Value As Byte())
_dpapiEncrypted AesKeyAsByte = Value
End Set
End Property
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnos tics.DebuggerSt epThrough()> Private Sub
InitializeCompo nent()
End Sub
Protected WithEvents cleartextTextBo x As
System.Web.UI.W ebControls.Text Box
Protected WithEvents ciphertextTextB ox As
System.Web.UI.W ebControls.Text Box
Protected WithEvents entropyCheckBox As
System.Web.UI.W ebControls.Chec kBox
Protected WithEvents encryptButton As System.Web.UI.W ebControls.Butt on
Protected WithEvents decryptButton As System.Web.UI.W ebControls.Butt on
Protected WithEvents generatedEntrop yTextBox As
System.Web.UI.W ebControls.Text Box
'NOTE: The following placeholder declaration is required by the Web Form
Designer.
'Do not delete or move it.
Private designerPlaceho lderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArg s) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeCompo nent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArg s) Handles MyBase.Load
'Put user code to initialize the page here
End Sub
Public Enum Store
USE_MACHINE_STO RE
USE_USER_STORE
End Enum
Friend Function CreateKey() As Byte()
'Create a new AES Service Provider
Dim aesProvider As New RijndaelManaged
'Declare the key size
aesProvider.Key Size = 256
aesProvider.Blo ckSize = 256
aesProvider.Pad ding = PaddingMode.PKC S7
aesProvider.Gen erateKey()
Return aesProvider.Key
End Function
Friend Function CreateEntropyVa lue() As Byte()
Dim rng As New RNGCryptoServic eProvider
Dim rng256EntropyBy teValue(31) As Byte
rng.GetBytes(rn g256EntropyByte Value)
Return rng256EntropyBy teValue
End Function
Private Sub encryptButton_C lick(ByVal sender As System.Object, ByVal e
As System.EventArg s) Handles encryptButton.C lick
Dim dp As New RindjaelTest.Mi crosoft.Win32.D PAPI.DataProtec tor
Dim AesKeyValueInBy tes(31) As Byte
AesKeyValueInBy tes = CreateKey()
generatedB64Aes Key.Text = Convert.ToBase6 4String(AesKeyV alueInBytes)
If entropyCheckBox .Checked Then
entropyValueAsB yte = CreateEntropyVa lue()
dpapiEncryptedA esKeyAsByte = dp.Encrypt(AesK eyValueInBytes,
entropyValueAsB yte, Store.USE_MACHI NE_STORE)
ciphertextTextB ox.Text =
Convert.ToBase6 4String(dpapiEn cryptedAesKeyAs Byte)
generatedEntrop yTextBox.Text =
Convert.ToBase6 4String(entropy ValueAsByte)
Else
dpapiEncryptedA esKeyAsByte = dp.Encrypt(AesK eyValueInBytes,
Nothing, Store.USE_MACHI NE_STORE)
ciphertextTextB ox.Text =
Convert.ToBase6 4String(dpapiEn cryptedAesKeyAs Byte)
End If
ciphertextTextB ox.Text.TrimEnd ()
End Sub
Private Sub decryptButton_C lick(ByVal sender As System.Object, ByVal e
As System.EventArg s) Handles decryptButton.C lick
If Not dpapiEncryptedA esKeyAsByte Is Nothing Then
Dim dp As New RindjaelTest.Mi crosoft.Win32.D PAPI.DataProtec tor
If entropyCheckBox .Checked Then
cleartextTextBo x.Text =
Convert.ToBase6 4String(dp.Decr ypt(dpapiEncryp tedAesKeyAsByte ,
entropyValueAsB yte, Store.USE_MACHI NE_STORE))
Else
cleartextTextBo x.Text =
Convert.ToBase6 4String(dp.Decr ypt(dpapiEncryp tedAesKeyAsByte , Nothing,
Store.USE_MACHI NE_STORE))
End If
cleartextTextBo x.Text.TrimEnd( )
End If
End Sub
End Class