├── .gitignore
├── LICENSE
├── README.md
├── Salsa20Cipher.plgx
├── Salsa20Cipher
├── Properties
│ └── AssemblyInfo.cs
├── Salsa20Cipher.csproj
├── Salsa20CipherExt.cs
├── Salsa20CryptoTransform.cs
└── Salsa20Engine.cs
├── Salsa20CipherPlugin.sln
├── make-plgx.bat
└── version-information.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-2016, Scott Bennett
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KeePass-SalsaCipher
2 |
3 | Enables KeePass to encrypt databases using the Salsa20 cipher. Just download
4 | the released `Salsa20Cipher.plgx` file and put it in the KeePass installation
5 | folder. KeePass should automatically recognize it as an available encryption
6 | algorithm.
7 |
8 | http://keepass.info/plugins.html
9 |
10 | ### Requirements
11 |
12 | * KeePass 2.18 or higher
13 | * .NET framework v3.0 or higher
14 |
15 | ### Build Info
16 |
17 | The released `Salsa20Cipher.plgx` is built using these options:
18 |
19 | `--plgx-prereq-kp:2.18 --plgx-prereq-os:Windows --plgx-prereq-net:3`
20 |
21 | See the [KeePass plugin development page](http://keepass.info/help/v2_dev/plg_index.html#plgx)
22 | for more information.
23 |
24 | ### Notes
25 |
26 | * This project was created with Visual Studio 2010
27 | * The plugin has only been tested on Windows 7
28 |
--------------------------------------------------------------------------------
/Salsa20Cipher.plgx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbennett1990/KeePass-SalsaCipher/91207eb901b6580db8e63f72413fa247ef26edd1/Salsa20Cipher.plgx
--------------------------------------------------------------------------------
/Salsa20Cipher/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Salsa20 Cipher")]
9 | [assembly: AssemblyDescription("Enables KeePass to encrypt databases using the Salsa20 algorithm.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Scott Bennett")]
12 | [assembly: AssemblyProduct("KeePass Plugin")]
13 | [assembly: AssemblyCopyright("Copyright (c) 2015 Scott Bennett")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("716E1C8A-EE17-4BDC-93AE-A977B882833A")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | [assembly: AssemblyVersion("0.6.1")]
33 | [assembly: AssemblyFileVersion("0.6.1")]
34 |
--------------------------------------------------------------------------------
/Salsa20Cipher/Salsa20Cipher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {A7DEAA9C-9BBB-474F-9467-FF150FC50BED}
9 | Library
10 | Properties
11 | Salsa20Cipher
12 | Salsa20Cipher
13 | v3.0
14 | 512
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | C:\Program Files (x86)\KeePass\KeePass.exe
37 | False
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
57 |
--------------------------------------------------------------------------------
/Salsa20Cipher/Salsa20CipherExt.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Scott Bennett
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | *
11 | * * Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 | */
26 |
27 | using KeePass.Plugins;
28 |
29 | namespace Salsa20Cipher {
30 | public sealed class Salsa20CipherExt : Plugin {
31 | private IPluginHost pluginHost = null;
32 | private const string updateUrl =
33 | "https://raw.githubusercontent.com/sbennett1990/KeePass-SalsaCipher/master/version-information.txt";
34 |
35 | private static Salsa20Engine salsa20CipherEngine = new Salsa20Engine();
36 |
37 | ///
38 | /// Access the URL of my version information file. (Read-Only)
39 | ///
40 | public override string UpdateUrl {
41 | get {
42 | return updateUrl;
43 | }
44 | }
45 |
46 | ///
47 | /// Initialize the Salsa20 Cipher plugin.
48 | ///
49 | /// The host application (i.e. KeePass 2.18)
50 | /// True for successful initialization; false otherwise
51 | public override bool Initialize(IPluginHost host) {
52 | if (host == null) {
53 | return false;
54 | }
55 |
56 | pluginHost = host;
57 |
58 | if (salsa20CipherEngine == null) {
59 | return false;
60 | }
61 |
62 | pluginHost.CipherPool.AddCipher(salsa20CipherEngine);
63 |
64 | return true;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Salsa20Cipher/Salsa20CryptoTransform.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-2013 Logos Bible Software
3 | *
4 | * This code is derived from software originally written by
5 | * Logos Bible Software.
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | */
25 |
26 | using System;
27 | using System.Security.Cryptography;
28 | using System.Text;
29 |
30 | namespace Salsa20Cipher {
31 | ///
32 | /// Salsa20 Stream Cipher
33 | ///
34 | public sealed class Salsa20CryptoTransform : ICryptoTransform {
35 | ///
36 | /// The Salsa20 state (aka "context")
37 | ///
38 | private uint[] state;
39 |
40 | ///
41 | /// The number of Salsa rounds to perform
42 | ///
43 | private readonly int numRounds;
44 |
45 | ///
46 | /// Set up a new Salsa20 state. The lengths of the given parameters are
47 | /// checked before encryption happens. A 32-byte (256-bit) key is required.
48 | /// The nonce (aka IV) must be at least 8-bytes (64-bits) long. If it is
49 | /// any larger, only the first 64 bits will be used.
50 | ///
51 | ///
52 | /// A 32-byte (256-bit) key, treated as a concatenation of eight 32-bit
53 | /// little-endian integers
54 | ///
55 | ///
56 | /// An 8-byte (64-bit) nonce, treated as a concatenation of two 32-bit
57 | /// little-endian integers
58 | ///
59 | public Salsa20CryptoTransform(byte[] key, byte[] iv) {
60 | if (key == null) {
61 | throw new ArgumentNullException("key");
62 | }
63 | if (iv == null) {
64 | throw new ArgumentNullException("iv");
65 | }
66 | if (key.Length != 32) {
67 | throw new ArgumentException(
68 | "Key length must be 32 bytes. Actual is " + key.Length.ToString()
69 | );
70 | }
71 | if (iv.Length < 8) {
72 | throw new ArgumentException(
73 | "Nonce should have 8 bytes. Actual is " + iv.Length.ToString()
74 | );
75 | }
76 |
77 | Initialize(key, iv);
78 | numRounds = 20;
79 | }
80 |
81 | ///
82 | /// Determine whether the current transform can be reused (Read-Only)
83 | ///
84 | public bool CanReuseTransform {
85 | get {
86 | return false;
87 | }
88 | }
89 |
90 | ///
91 | /// Determine whether multiple blocks can be transformed (Read-Only)
92 | ///
93 | public bool CanTransformMultipleBlocks {
94 | get {
95 | return true;
96 | }
97 | }
98 |
99 | ///
100 | /// Get the input block size, in bytes (Read-Only)
101 | ///
102 | public int InputBlockSize {
103 | get {
104 | return 64;
105 | }
106 | }
107 |
108 | ///
109 | /// Get the output block size, in bytes (Read-Only)
110 | ///
111 | public int OutputBlockSize {
112 | get {
113 | return 64;
114 | }
115 | }
116 |
117 | ///
118 | /// Initialize the Salsa state with the given key and nonce (aka
119 | /// Initialization Vector or IV). A 32-byte (256-bit) key is required. The
120 | /// nonce must be at least 8-bytes (64-bits) long. If it is any larger,
121 | /// only the first 64 bits will be used.
122 | ///
123 | ///
124 | /// A 32-byte (256-bit) key, treated as a concatenation of eight 32-bit
125 | /// little-endian integers
126 | ///
127 | ///
128 | /// An 8-byte (64-bit) nonce, treated as a concatenation of two 32-bit
129 | /// little-endian integers
130 | ///
131 | private void Initialize(byte[] key, byte[] iv) {
132 | state = new uint[16];
133 |
134 | state[1] = ToUInt32(key, 0);
135 | state[2] = ToUInt32(key, 4);
136 | state[3] = ToUInt32(key, 8);
137 | state[4] = ToUInt32(key, 12);
138 |
139 | // These are the same constants defined in the reference implementation
140 | // see http://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c
141 | byte[] sigma = Encoding.ASCII.GetBytes("expand 32-byte k");
142 | byte[] tau = Encoding.ASCII.GetBytes("expand 16-byte k");
143 |
144 | byte[] constants = (key.Length == 32) ? sigma : tau;
145 | int keyIndex = key.Length - 16;
146 |
147 | state[11] = ToUInt32(key, keyIndex + 0);
148 | state[12] = ToUInt32(key, keyIndex + 4);
149 | state[13] = ToUInt32(key, keyIndex + 8);
150 | state[14] = ToUInt32(key, keyIndex + 12);
151 |
152 | state[0] = ToUInt32(constants, 0);
153 | state[5] = ToUInt32(constants, 4);
154 | state[10] = ToUInt32(constants, 8);
155 | state[15] = ToUInt32(constants, 12);
156 |
157 | state[6] = ToUInt32(iv, 0);
158 | state[7] = ToUInt32(iv, 4);
159 | state[8] = 0;
160 | state[9] = 0;
161 | }
162 |
163 | ///
164 | /// Encrypt an arbitrary-length plaintext message (inputBuffer), writing the
165 | /// resulting ciphertext to the outputBuffer. The number of bytes to read
166 | /// from the input buffer is determined by inputCount.
167 | ///
168 | ///
169 | ///
170 | ///
171 | ///
172 | ///
173 | /// The number of bytes written
174 | public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
175 | /* Check the parameters */
176 | if (inputBuffer == null) {
177 | throw new ArgumentNullException("inputBuffer");
178 | }
179 | if (inputOffset < 0 || inputOffset >= inputBuffer.Length) {
180 | throw new ArgumentOutOfRangeException("inputOffset");
181 | }
182 | if (inputCount < 0 || (inputOffset + inputCount) > inputBuffer.Length) {
183 | throw new ArgumentOutOfRangeException("inputCount");
184 | }
185 | if (outputBuffer == null) {
186 | throw new ArgumentNullException("outputBuffer");
187 | }
188 | if (outputOffset < 0 || (outputOffset + inputCount) > outputBuffer.Length) {
189 | throw new ArgumentOutOfRangeException("outputOffset");
190 | }
191 | if (state == null) {
192 | throw new ObjectDisposedException(GetType().Name);
193 | }
194 |
195 | byte[] output = new byte[64];
196 | int bytesTransformed = 0;
197 |
198 | while (inputCount > 0) {
199 | Salsa20Core(output, state);
200 |
201 | state[8] = AddOne(state[8]);
202 | if (state[8] == 0) {
203 | /* Stopping at 2^70 bytes per nonce is the user's responsibility */
204 | state[9] = AddOne(state[9]);
205 | }
206 |
207 | int blockSize = Math.Min(64, inputCount);
208 |
209 | for (int i = 0; i < blockSize; i++) {
210 | outputBuffer[outputOffset + i] = (byte) (inputBuffer[inputOffset + i] ^ output[i]);
211 | }
212 |
213 | bytesTransformed += blockSize;
214 |
215 | inputCount -= 64;
216 | outputOffset += 64;
217 | inputOffset += 64;
218 | }
219 |
220 | return bytesTransformed;
221 | }
222 |
223 | ///
224 | /// Transforms the specified region of the specified byte array.
225 | ///
226 | ///
227 | ///
228 | ///
229 | /// The computed transform
230 | public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
231 | // No parameter checking needed as that is handled in TransformBlock()
232 |
233 | byte[] output = new byte[inputCount];
234 | TransformBlock(inputBuffer, inputOffset, inputCount, output, 0);
235 |
236 | return output;
237 | }
238 |
239 | ///
240 | /// Clear and dispose of the internal Salsa state.
241 | ///
242 | public void Dispose() {
243 | if (state != null) {
244 | Array.Clear(state, 0, state.Length);
245 | }
246 |
247 | state = null;
248 | }
249 |
250 | ///
251 | /// The Salsa20 Core Function reads a 64-byte vector x and produces a 64-byte
252 | /// vector Salsa20(x). This is the basis of the Salsa20 Stream Cipher.
253 | ///
254 | ///
255 | /// See the Salsa20 core page
256 | /// for more detailed information about the Salsa20 core function.
257 | ///
258 | ///
259 | ///
260 | private void Salsa20Core(byte[] output, uint[] input) {
261 | uint[] tmp = (uint[]) input.Clone();
262 |
263 | for (int i = numRounds; i > 0; i -= 2) {
264 | tmp[4] ^= Rotate(Add(tmp[0], tmp[12]), 7);
265 | tmp[8] ^= Rotate(Add(tmp[4], tmp[0]), 9);
266 | tmp[12] ^= Rotate(Add(tmp[8], tmp[4]), 13);
267 | tmp[0] ^= Rotate(Add(tmp[12], tmp[8]), 18);
268 | tmp[9] ^= Rotate(Add(tmp[5], tmp[1]), 7);
269 | tmp[13] ^= Rotate(Add(tmp[9], tmp[5]), 9);
270 | tmp[1] ^= Rotate(Add(tmp[13], tmp[9]), 13);
271 | tmp[5] ^= Rotate(Add(tmp[1], tmp[13]), 18);
272 | tmp[14] ^= Rotate(Add(tmp[10], tmp[6]), 7);
273 | tmp[2] ^= Rotate(Add(tmp[14], tmp[10]), 9);
274 | tmp[6] ^= Rotate(Add(tmp[2], tmp[14]), 13);
275 | tmp[10] ^= Rotate(Add(tmp[6], tmp[2]), 18);
276 | tmp[3] ^= Rotate(Add(tmp[15], tmp[11]), 7);
277 | tmp[7] ^= Rotate(Add(tmp[3], tmp[15]), 9);
278 | tmp[11] ^= Rotate(Add(tmp[7], tmp[3]), 13);
279 | tmp[15] ^= Rotate(Add(tmp[11], tmp[7]), 18);
280 | tmp[1] ^= Rotate(Add(tmp[0], tmp[3]), 7);
281 | tmp[2] ^= Rotate(Add(tmp[1], tmp[0]), 9);
282 | tmp[3] ^= Rotate(Add(tmp[2], tmp[1]), 13);
283 | tmp[0] ^= Rotate(Add(tmp[3], tmp[2]), 18);
284 | tmp[6] ^= Rotate(Add(tmp[5], tmp[4]), 7);
285 | tmp[7] ^= Rotate(Add(tmp[6], tmp[5]), 9);
286 | tmp[4] ^= Rotate(Add(tmp[7], tmp[6]), 13);
287 | tmp[5] ^= Rotate(Add(tmp[4], tmp[7]), 18);
288 | tmp[11] ^= Rotate(Add(tmp[10], tmp[9]), 7);
289 | tmp[8] ^= Rotate(Add(tmp[11], tmp[10]), 9);
290 | tmp[9] ^= Rotate(Add(tmp[8], tmp[11]), 13);
291 | tmp[10] ^= Rotate(Add(tmp[9], tmp[8]), 18);
292 | tmp[12] ^= Rotate(Add(tmp[15], tmp[14]), 7);
293 | tmp[13] ^= Rotate(Add(tmp[12], tmp[15]), 9);
294 | tmp[14] ^= Rotate(Add(tmp[13], tmp[12]), 13);
295 | tmp[15] ^= Rotate(Add(tmp[14], tmp[13]), 18);
296 | }
297 |
298 | for (int i = 0; i < 16; i++) {
299 | ToBytes(Add(tmp[i], input[i]), output, 4 * i);
300 | }
301 | }
302 |
303 | ///
304 | /// n-bit left rotation operation (towards the high bits) for 32-bit
305 | /// integers.
306 | ///
307 | ///
308 | ///
309 | /// The result of (v LEFTSHIFT c)
310 | private static uint Rotate(uint v, int c) {
311 | return (v << c) | (v >> (32 - c));
312 | }
313 |
314 | ///
315 | /// Unchecked integer addition. The Salsa spec defines certain operations
316 | /// to use 32-bit unsigned integer addition modulo 2^32.
317 | ///
318 | ///
319 | ///
320 | /// The result of (v + w) modulo 2^32
321 | private static uint Add(uint v, uint w) {
322 | return unchecked(v + w);
323 | }
324 |
325 | ///
326 | /// Add 1 to the input parameter using unchecked integer addition. The
327 | /// Salsa spec defines certain operations to use 32-bit unsigned integer
328 | /// addition modulo 2^32.
329 | ///
330 | ///
331 | /// The result of (v + 1) modulo 2^32
332 | private static uint AddOne(uint v) {
333 | return unchecked(v + 1);
334 | }
335 |
336 | ///
337 | /// Convert four bytes of the input buffer into an unsigned
338 | /// 32-bit integer, beginning at the inputOffset.
339 | ///
340 | ///
341 | ///
342 | /// An unsigned 32-bit integer
343 | private static uint ToUInt32(byte[] input, int inputOffset) {
344 | unchecked {
345 | return (uint) (((input[inputOffset] |
346 | (input[inputOffset + 1] << 8)) |
347 | (input[inputOffset + 2] << 16)) |
348 | (input[inputOffset + 3] << 24));
349 | }
350 | }
351 |
352 | ///
353 | /// Serialize the input integer into the output buffer. The input integer
354 | /// will be split into 4 bytes and put into four sequential places in the
355 | /// output buffer, starting at the outputOffset.
356 | ///
357 | ///
358 | ///
359 | ///
360 | private static void ToBytes(uint input, byte[] output, int outputOffset) {
361 | unchecked {
362 | output[outputOffset] = (byte) input;
363 | output[outputOffset + 1] = (byte) (input >> 8);
364 | output[outputOffset + 2] = (byte) (input >> 16);
365 | output[outputOffset + 3] = (byte) (input >> 24);
366 | }
367 | }
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/Salsa20Cipher/Salsa20Engine.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Scott Bennett
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | *
11 | * * Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 | */
26 |
27 | using System.IO;
28 | using System.Security.Cryptography;
29 |
30 | using KeePassLib;
31 | using KeePassLib.Cryptography.Cipher;
32 |
33 | namespace Salsa20Cipher {
34 | public sealed class Salsa20Engine : ICipherEngine {
35 | private PwUuid uuidCipher;
36 | private const string cipherName = "Salsa20 Cipher";
37 |
38 | private static readonly byte[] Salsa20UuidBytes = new byte[] {
39 | 0x71, 0x6E, 0x1C, 0x8A, 0xEE, 0x17, 0x4B, 0xDC,
40 | 0x93, 0xAE, 0xA9, 0x77, 0xB8, 0x82, 0x83, 0x3A
41 | };
42 |
43 | ///
44 | /// Basic constructor
45 | ///
46 | public Salsa20Engine() {
47 | uuidCipher = new PwUuid(Salsa20UuidBytes);
48 | }
49 |
50 | ///
51 | /// Access this Cipher's UUID.
52 | ///
53 | public PwUuid CipherUuid {
54 | get {
55 | return uuidCipher;
56 | }
57 | }
58 |
59 | ///
60 | /// Access this Cipher's name.
61 | ///
62 | public string DisplayName {
63 | get {
64 | return cipherName;
65 | }
66 | }
67 |
68 | ///
69 | /// Encrypt the incoming plainTextStream.
70 | ///
71 | ///
72 | ///
73 | ///
74 | /// An encrypted stream of bytes
75 | public Stream EncryptStream(Stream plainTextStream, byte[] key, byte[] iv) {
76 | ICryptoTransform iTransform = new Salsa20CryptoTransform(key, iv);
77 |
78 | return new CryptoStream(plainTextStream, iTransform, CryptoStreamMode.Write);
79 | }
80 |
81 | ///
82 | /// Decrypt the incoming encryptedStream.
83 | ///
84 | ///
85 | ///
86 | ///
87 | /// The plaintext stream derived from encrypted stream
88 | public Stream DecryptStream(Stream encryptedStream, byte[] key, byte[] iv) {
89 | ICryptoTransform iTransform = new Salsa20CryptoTransform(key, iv);
90 |
91 | return new CryptoStream(encryptedStream, iTransform, CryptoStreamMode.Read);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Salsa20CipherPlugin.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Salsa20Cipher", "Salsa20Cipher\Salsa20Cipher.csproj", "{A7DEAA9C-9BBB-474F-9467-FF150FC50BED}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {A7DEAA9C-9BBB-474F-9467-FF150FC50BED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {A7DEAA9C-9BBB-474F-9467-FF150FC50BED}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {A7DEAA9C-9BBB-474F-9467-FF150FC50BED}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {A7DEAA9C-9BBB-474F-9467-FF150FC50BED}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/make-plgx.bat:
--------------------------------------------------------------------------------
1 | :: This build file is very rigid and highly un-portable. I use is as a convenience on my own computer.
2 | :: Note to self: Run this file within the KeePass directory!
3 |
4 | SET basefolder=C:\Users\%username%\Documents\Code\GitHub\KeePass-SalsaCipher
5 | SET srcfolder=%basefolder%\Salsa20Cipher
6 | SET plgx=%basefolder%\Salsa20Cipher.plgx
7 |
8 | rd %srcfolder%\bin /S /Q
9 | rd %srcfolder%\obj /S /Q
10 |
11 | .\KeePass.exe --plgx-create %srcfolder% --plgx-prereq-kp:2.18 --plgx-prereq-os:Windows --plgx-prereq-net:3
12 |
13 | xcopy %plgx% /Y
14 |
--------------------------------------------------------------------------------
/version-information.txt:
--------------------------------------------------------------------------------
1 | :
2 | Salsa20 Cipher:0.6.0
3 | :
--------------------------------------------------------------------------------