File: Protocol.cs

package info (click to toggle)
keepass2-plugin-keepasshttp 1.8.4.2%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,816 kB
  • sloc: cs: 2,273; makefile: 7
file content (224 lines) | stat: -rw-r--r-- 7,172 bytes parent folder | download | duplicates (2)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

using KeePass.Plugins;
using System.Reflection;
using System.Diagnostics;

namespace KeePassHttp
{
    public sealed partial class KeePassHttpExt : Plugin
    {
        private static string encode64(byte[] b)
        {
            return System.Convert.ToBase64String(b);
        }

        private static byte[] decode64(string s)
        {
            return System.Convert.FromBase64String(s);
        }
        private bool VerifyRequest(Request r, Aes aes)
        {
            var entry = GetConfigEntry(false);
            if (entry == null)
                return false;
            var s = entry.Strings.Get(ASSOCIATE_KEY_PREFIX + r.Id);
            if (s == null)
                return false;

            return TestRequestVerifier(r, aes, s.ReadString());
        }

        private bool TestRequestVerifier(Request r, Aes aes, string key)
        {
            var success = false;
            var crypted = decode64(r.Verifier);

            aes.Key = decode64(key);
            aes.IV = decode64(r.Nonce);

            using (var dec = aes.CreateDecryptor())
            {
                try {
                    var buf = dec.TransformFinalBlock(crypted, 0, crypted.Length);
                    var value = Encoding.UTF8.GetString(buf);
                    success = value == r.Nonce;
                } catch (CryptographicException) { } // implicit failure
            }
            return success;
        }

        private void SetResponseVerifier(Response r, Aes aes)
        {
            aes.GenerateIV();
            r.Nonce = encode64(aes.IV);
            r.Verifier = CryptoTransform(r.Nonce, false, true, aes, CMode.ENCRYPT);
        }
    }
    public class Request
    {
        public const string GET_LOGINS = "get-logins";
        public const string GET_LOGINS_COUNT = "get-logins-count";
        public const string GET_ALL_LOGINS = "get-all-logins";
        public const string SET_LOGIN = "set-login";
        public const string ASSOCIATE = "associate";
        public const string TEST_ASSOCIATE = "test-associate";
        public const string GENERATE_PASSWORD = "generate-password";

        public string RequestType;

        /// <summary>
        /// Sort selection by best URL matching for given hosts
        /// </summary>
        public string SortSelection;

        /// <summary>
        /// Trigger unlock of database even if feature is disabled in KPH (because of user interaction to fill-in)
        /// </summary>
        public string TriggerUnlock;

        /// <summary>
        /// Always encrypted, used with set-login, uuid is set
        /// if modifying an existing login
        /// </summary>
        public string Login;
        public string Password;
        public string Uuid;

        /// <summary>
        /// Always encrypted, used with get and set-login
        /// </summary>
        public string Url;

        /// <summary>
        /// Always encrypted, used with get-login
        /// </summary>
        public string SubmitUrl;

        /// <summary>
        /// Send the AES key ID with the 'associate' request
        /// </summary>
        public string Key;

        /// <summary>
        /// Always required, an identifier given by the KeePass user
        /// </summary>
        public string Id;
        /// <summary>
        /// A value used to ensure that the correct key has been chosen,
        /// it is always the value of Nonce encrypted with Key
        /// </summary>
        public string Verifier;
        /// <summary>
        /// Nonce value used in conjunction with all encrypted fields,
        /// randomly generated for each request
        /// </summary>
        public string Nonce;

        /// <summary>
        /// Realm value used for filtering results.  Always encrypted.
        /// </summary>
        public string Realm;
    }

    public class Response
    {
        public Response(string request, string hash)
        {
            RequestType = request;

            if (request == Request.GET_LOGINS || request == Request.GET_ALL_LOGINS || request == Request.GENERATE_PASSWORD)
                Entries = new List<ResponseEntry>();
            else
                Entries = null;

            Assembly assembly = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            this.Version = fvi.ProductVersion;

            this.Hash = hash;
        }

        /// <summary>
        /// Mirrors the request type of KeePassRequest
        /// </summary>
        public string RequestType;

        public string Error = null;

        public bool Success = false;

        /// <summary>
        /// The user selected string as a result of 'associate',
        /// always returned on every request
        /// </summary>
        public string Id;

        /// <summary>
        /// response to get-logins-count, number of entries for requested Url
        /// </summary>
        public int Count = 0;

        /// <summary>
        /// response the current version of KeePassHttp
        /// </summary>
        public string Version = "";

        /// <summary>
        /// response an unique hash of the database composed of RootGroup UUid and RecycleBin UUid
        /// </summary>
        public string Hash = "";

        /// <summary>
        /// The resulting entries for a get-login request
        /// </summary>
        public List<ResponseEntry> Entries { get; private set; }

        /// <summary>
        /// Nonce value used in conjunction with all encrypted fields,
        /// randomly generated for each request
        /// </summary>
        public string Nonce;

        /// <summary>
        /// Same purpose as Request.Verifier, but a new value
        /// </summary>
        public string Verifier;
    }
    public class ResponseEntry
    {
        public ResponseEntry() { }
        public ResponseEntry(string name, string login, string password, string uuid, List<ResponseStringField> stringFields)
        {
            Login = login;
            Password = password;
            Uuid = uuid;
            Name = name;
            StringFields = stringFields;
        }
        public string Login;
        public string Password;
        public string Uuid;
        public string Name;
        public List<ResponseStringField> StringFields = null;
    }
    public class ResponseStringField
    {
        public ResponseStringField() {}
        public ResponseStringField(string key, string value)
        {
            Key = key;
            Value = value;
        }
        public string Key;
        public string Value;
    }
    public class KeePassHttpEntryConfig
    {
        public HashSet<string> Allow = new HashSet<string>();
        public HashSet<string> Deny = new HashSet<string>();
        public string Realm = null;
    }
}