-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path13_TemplateMethod.ps1
More file actions
118 lines (101 loc) · 4.49 KB
/
13_TemplateMethod.ps1
File metadata and controls
118 lines (101 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<#
.SYNOPSIS
OOP Reference: Template Method Pattern
.DESCRIPTION
Topic: Base class defines algorithm skeleton; subclasses fill steps
Category: Behavioral
Agent Task: Add a third workflow subclass: ZstdAesWorkflow that uses
System.IO.Compression.ZLibStream for compression.
Add Pester tests verifying the sequence fires in order.
Use a [System.Collections.Generic.List[string]] step log in the base class.
Done Conditions:
- Execute() sequence cannot be reordered by subclass
- Step log records Validate->Compress->Encrypt->Sign->Package->Audit in order
- Pester tests pass: Invoke-Pester -Output Detailed
Non-Scope:
- Do not parallelize steps
#>
class CryptoWorkflow {
hidden [System.Collections.Generic.List[string]]$_stepLog
CryptoWorkflow() {
$this._stepLog = [System.Collections.Generic.List[string]]::new()
}
# Template method — sequence is invariant
[hashtable] Execute([byte[]]$plaintext) {
$validated = $this._Step('Validate', { $this.Validate($plaintext) })
$compressed = $this._Step('Compress', { $this.Compress($validated) })
$encrypted = $this._Step('Encrypt', { $this.Encrypt($compressed) })
$signed = $this._Step('Sign', { $this.Sign($encrypted) })
$result = $this._Step('Package', { $this.Package($signed) })
$this._Step('Audit', { $this.Audit($result); $result })
return $result
}
hidden [object] _Step([string]$name, [scriptblock]$action) {
$this._stepLog.Add($name)
return & $action
}
[string[]] GetStepLog() { return $this._stepLog.ToArray() }
hidden [byte[]] Validate([byte[]]$data) {
if ($data.Length -eq 0) { throw [System.ArgumentException]'Empty payload' }
return $data
}
hidden [byte[]] Compress([byte[]]$data) { return $data }
hidden [byte[]] Encrypt([byte[]]$data) { throw [System.NotImplementedException]'Encrypt' }
hidden [byte[]] Sign([byte[]]$data) { throw [System.NotImplementedException]'Sign' }
hidden [hashtable] Package([byte[]]$data) {
return @{ Payload=$data; Timestamp=[datetime]::UtcNow; Version=1 }
}
hidden [void] Audit([hashtable]$result) { }
}
class GzipAesWorkflow : CryptoWorkflow {
hidden [byte[]]$_key
GzipAesWorkflow() : base() {
$this._key = [byte[]]::new(32)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($this._key)
}
hidden [byte[]] Compress([byte[]]$data) {
$ms = [System.IO.MemoryStream]::new()
$gz = [System.IO.Compression.GZipStream]::new($ms,
[System.IO.Compression.CompressionMode]::Compress)
$gz.Write($data, 0, $data.Length); $gz.Dispose()
return $ms.ToArray()
}
hidden [byte[]] Encrypt([byte[]]$data) {
$gcm = [System.Security.Cryptography.AesGcm]::new($this._key)
$nonce = [byte[]]::new(12); $ct = [byte[]]::new($data.Length); $tag = [byte[]]::new(16)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($nonce)
$gcm.Encrypt($nonce, $data, $ct, $tag); $gcm.Dispose()
return $nonce + $tag + $ct
}
hidden [byte[]] Sign([byte[]]$data) {
$hmac = [System.Security.Cryptography.HMACSHA256]::new($this._key)
$mac = $hmac.ComputeHash($data); $hmac.Dispose()
return $mac + $data
}
}
class ZstdAesWorkflow : CryptoWorkflow {
hidden [byte[]]$_key
ZstdAesWorkflow() : base() {
$this._key = [byte[]]::new(32)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($this._key)
}
hidden [byte[]] Compress([byte[]]$data) {
$ms = [System.IO.MemoryStream]::new()
$zlib = [System.IO.Compression.ZLibStream]::new($ms,
[System.IO.Compression.CompressionMode]::Compress)
$zlib.Write($data, 0, $data.Length); $zlib.Dispose()
return $ms.ToArray()
}
hidden [byte[]] Encrypt([byte[]]$data) {
$gcm = [System.Security.Cryptography.AesGcm]::new($this._key)
$nonce = [byte[]]::new(12); $ct = [byte[]]::new($data.Length); $tag = [byte[]]::new(16)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($nonce)
$gcm.Encrypt($nonce, $data, $ct, $tag); $gcm.Dispose()
return $nonce + $tag + $ct
}
hidden [byte[]] Sign([byte[]]$data) {
$hmac = [System.Security.Cryptography.HMACSHA256]::new($this._key)
$mac = $hmac.ComputeHash($data); $hmac.Dispose()
return $mac + $data
}
}