When I pass a byte array directly to he function it works as expected. When I create a new instance of my custom class and pass the same blob to the function, I get this error
FindInArray : Cannot process argument transformation on parameter 'source'. Cannot convert the "System.Byte[]" value
of type "System.Byte[]" to type "System.Byte".
At line:89 char:22
+ $pos = FindInArray($blob, $HashAsn[[HashAlgs]::$enum])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [FindInArray], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,FindInArray
If I remove the type designation in the FindArray function definition, then it seems to work, but I don't think I should have to do that
In case it isn't clear: I want to have this class create a new instance either from nothing or from an existing blob. To parse an existing blob, I need to search the blob for instances of the enums. I'm trying to 'cheat' by working with the binary ASN1 data rather than decoding/encoding it
My code
function FindInArray([byte[]]$source, [byte[]]$find) {
if ($find.Length -gt $source.Length) { throw 'search bytes are longer than source' }
$end = $source.Length - $find.Length
$iFound = -1
for ($pos = 0; ($iFound -eq -1) -and ($pos -le ($end)); $pos++) {
if ($source[$pos] -eq $find[0]) {
$iFound = $pos
for ($pos2 = 1; $pos2 -lt $find.Length; $pos2++) {
if ($source[$pos + $pos2] -ne $find[$pos2]) {$iFound = -1; break}
}
}
}
return $iFound
}
[Flags()] enum CryptAlgs {
AES_256 = 1
AES_192 = 2
TripleDES = 4
AES_128 = 8
RC2_128 = 16
RC2_64 = 32
}
# I could not figure out how to assign these during initialization so we'll just do them one-by-one >:-[
$CryptAsn = @{}
$CryptAsn[[CryptAlgs]::AES_256] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A)
$CryptAsn[[CryptAlgs]::AES_192] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16)
$CryptAsn[[CryptAlgs]::TripleDES] = [byte[]]@(0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07)
$CryptAsn[[CryptAlgs]::AES_128] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02)
$CryptAsn[[CryptAlgs]::RC2_128] = [byte[]]@(0x30, 0x0E, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80)
$CryptAsn[[CryptAlgs]::RC2_64] = [byte[]]@(0x30, 0x0D, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02, 0x02, 0x01, 0x40)
[Flags()] enum HashAlgs {
SHA1 = 1
SHA_512 = 2
SHA_384 = 4
SHA_256 = 8
}
$HashAsn = @{}
$HashAsn[[HashAlgs]::SHA1] = [byte[]]@(0x30, 0x07, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A)
$HashAsn[[HashAlgs]::SHA_512] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03)
$HashAsn[[HashAlgs]::SHA_384] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02)
$HashAsn[[HashAlgs]::SHA_256] = [byte[]]@(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)
[Flags()] enum ESConfigOption {
Default1 = 1
Default2 = 2
SendWithMsgs = 4
}
class ESAlgorithmAsn {
[CryptAlgs]$EncryptionAlgorithm
[CryptAlgs]$OtherEncryptionAlgorithms
[HashAlgs]$HashAlgorithm
[HashAlgs]$OtherHashAlgorithms
ESAlgorithmAsn() {
$this.EncryptionAlgorithm = [CryptAlgs]::AES_256
$this.HashAlgorithm = [HashAlgs]::SHA_512
}
ESAlgorithmAsn([byte[]]$blob) {
$CryptAsn = $Global:CryptAsn
$HashAsn = $Global:HashAsn
$firstEnum = 0
$firstPos = -1
foreach ($enum in [CryptAlgs].GetEnumNames()) {
$pos = FindInArray($blob, $CryptAsn[[CryptAlgs]::$enum])
if ($pos -ne -1) {
$this.OtherEncryptionAlgorithms += [CryptAlgs]::$enum
if (($firstPos -eq -1) -or ($pos -lt $firstPos)) {
$firstPos = $pos
$firstEnum = [CryptAlgs]::$enum
}
}
}
$this.EncryptionAlgorithm = $firstEnum
$this.OtherEncryptionAlgorithms -= $firstEnum
foreach ($enum in [HashAlgs].GetEnumNames()) {
$pos = FindInArray([byte[]]$blob, $HashAsn[[HashAlgs]::$enum])
if ($pos -ne -1) {
$this.OtherHashAlgorithms += [HashAlgs]::$enum
if (($firstPos -eq -1) -or ($pos -lt $firstPos)) {
$firstPos = $pos
$firstEnum = [HashAlgs]::$enum
}
}
}
$this.HashAlgorithm = $firstEnum
$this.OtherHashAlgorithms -= $firstEnum
}
[byte[]]GetBytes() {
$CryptAsn = $Global:CryptAsn
$HashAsn = $Global:HashAsn
[uint32]$size = 0
$outputArray = $null
$pos = 0
$defaultHash = $null
$defaultCrypt = $null
if ($this.HashAlgorithm -eq 0) {throw 'Must include default hash algorithm'}
if ($this.CryptAlgorithm -eq 0) {throw 'Must include default encryption algorithm'}
if ($this.HashAlgorithm -band $this.OtherHashAlgorithms) {$this.OtherHashAlgorithms -= $this.HashAlgorithm}
if ($this.CryptAlgorithm -band $this.OtherEncryptionAlgorithms) {$this.OtherEncryptionAlgorithms -= $this.CryptAlgorithm}
foreach ($enum in [HashAlgs].GetEnumNames()) {
if ($this.HashAlgorithm -band [HashAlgs]::$enum) {
if ($defaultHash) {
throw 'Cannot set multiple default Hash Algorithms'
} else {
$defaultHash = $HashAsn[[HashAlgs]::$this.HashAlgorithm]
$size += $defaultHash.Length
}
}
if ($this.OtherHashAlgorithms -band [HashAlgs]::$enum){$size += $HashAsn[[HashAlgs]::$enum].length}
}
foreach ($enum in [CryptAlgs].GetEnumNames()) {
if ($this.CryptAlgorithm -band [CryptAlgs]::$enum) {
if ($defaultCrypt) {
throw 'Cannot set multiple default Encryption Algorithms'
} else {
$defaultCrypt = $CryptAsn[[CryptAlgs]::$this.CryptAlgorithm]
$size += $defaultCrypt.Length
}
}
if ($this.OtherEncryptionAlgorithms -band [CryptAlgs]::$enum) {$size += $CryptAsn[[CryptAlgs]::$enum].length}
}
#I can't imagine this string being longer than 65535 but we're going to code for it anyway
$sizeBytes = [bitconverter]::GetBytes($size)
$pos = 2
if ($size -lt 0x80) {
$outputArray = [byte[]]::new($size + $pos)
$outputArray[0] = [bitconverter]::GetBytes(0x30)[0]
$outputArray[1] = [bitconverter]::GetBytes($size)[0]
} else {
#When total length is greater than 0x80, we have to set the greatest bit and use the
# rest of the byte to define how many bytes needed to express the total size
# For example: if total size is 0xFF00FF then the ASN1 header will look like this
# 0x0 = 0x30
# 0x1 = 0x83 <- 0x80 || 0x03 for 3 bytes to express FF00FF
# 0x30 0x83 0xFF 0x00 0xFF <rest of ASN1 data>
#Find the last non-zero byte
$iSize = 0
foreach ($i in ($sizeBytes.Length - 1)..0) {if ($sizeBytes[$i]) {$iSize = $i; break}}
$outputArray = [byte[]]::new($size + $pos + $iSize + 1)
$outputArray[0] = [bitconverter]::GetBytes(0x30)[0]
$outputArray[1] = [bitconverter]::GetBytes(0x80 + $iSize + 1)[0]
# ASN1 stores numbers in Big-Endian so we need to reverse the array
foreach ($i in $iSize..0) {
$outputArray[$pos++] = $sizeBytes[$i] #Set the byte at $pos and then move to the next byte
}
}
# Header is complete, now we can compile the ASN1 data
$defaultCrypt.CopyTo($outputArray, $pos)
$pos += $defaultCrypt.Length
if ($this.OtherEncryptionAlgorithms) {
foreach ($enum in [CryptAlgs].GetEnumNames()) {
if ($this.OtherEncryptionAlgorithms -band [CryptAlgs]::$enum) {
$addBytes = $CryptAsn[[CryptAlgs]::$enum]
$addBytes.CopyTo($outputArray, $pos)
$pos += $addBytes.Length
}
}
}
$defaultHash.CopyTo($outputArray, $pos)
$pos += $defaultHash.Length
if ($this.OtherHashAlgorithms) {
foreach ($enum in [HashAlgs].GetEnumNames()) {
if ($this.OtherHashAlgorithms -band [HashAlgs]::$enum) {
$addBytes = $HashAsn[[HashAlgs]::$enum]
$addBytes.CopyTo($outputArray, $pos)
$pos += $addBytes.Length
}
}
}
return $outputArray
}
}
And the test blob
[byte[]]$blb = @(0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02)