Coverage for tests/__init__.py: 100.000%

58 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-07-14 11:39 +0200

1# SPDX-FileCopyrightText: 2024 Marco Ricci <m@the13thletter.info> 

2# 

3# SPDX-License-Identifier: MIT 

4 

5from __future__ import annotations 

6 

7import base64 

8from collections.abc import Iterator, Mapping 

9import contextlib 

10import json 

11import os 

12from typing import TYPE_CHECKING 

13from typing_extensions import Any, TypedDict 

14 

15import click.testing 

16import derivepassphrase 

17import derivepassphrase.cli 

18import derivepassphrase.types 

19import pytest 

20import ssh_agent_client 

21import ssh_agent_client.types 

22 

23__all__ = () 

24 

25if TYPE_CHECKING: 

26 class SSHTestKey(TypedDict): 

27 private_key: bytes 

28 public_key: bytes | str 

29 public_key_data: bytes 

30 expected_signature: bytes | None 

31 derived_passphrase: bytes | str | None 

32 

33SUPPORTED_KEYS: Mapping[str, SSHTestKey] = { 

34 'ed25519': { 

35 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

36b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 

37QyNTUxOQAAACCBeIFoJtYCSF8P/zJIb+TBMIncHGpFBgnpCQ/7whJpdgAAAKDweO7H8Hju 

38xwAAAAtzc2gtZWQyNTUxOQAAACCBeIFoJtYCSF8P/zJIb+TBMIncHGpFBgnpCQ/7whJpdg 

39AAAEAbM/A869nkWZbe2tp3Dm/L6gitvmpH/aRZt8sBII3ExYF4gWgm1gJIXw//Mkhv5MEw 

40idwcakUGCekJD/vCEml2AAAAG3Rlc3Qga2V5IHdpdGhvdXQgcGFzc3BocmFzZQEC 

41-----END OPENSSH PRIVATE KEY----- 

42''', 

43 'public_key': rb'''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIF4gWgm1gJIXw//Mkhv5MEwidwcakUGCekJD/vCEml2 test key without passphrase 

44''', 

45 'public_key_data': bytes.fromhex(''' 

46 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39 

47 00 00 00 20 

48 81 78 81 68 26 d6 02 48 5f 0f ff 32 48 6f e4 c1 

49 30 89 dc 1c 6a 45 06 09 e9 09 0f fb c2 12 69 76 

50'''), 

51 'expected_signature': bytes.fromhex(''' 

52 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39 

53 00 00 00 40 

54 f0 98 19 80 6c 1a 97 d5 26 03 6e cc e3 65 8f 86 

55 66 07 13 19 13 09 21 33 33 f9 e4 36 53 1d af fd 

56 0d 08 1f ec f8 73 9b 8c 5f 55 39 16 7c 53 54 2c 

57 1e 52 bb 30 ed 7f 89 e2 2f 69 51 55 d8 9e a6 02 

58 '''), 

59 'derived_passphrase': rb'8JgZgGwal9UmA27M42WPhmYHExkTCSEzM/nkNlMdr/0NCB/s+HObjF9VORZ8U1QsHlK7MO1/ieIvaVFV2J6mAg==', 

60 }, 

61 # Currently only supported by PuTTY (which is deficient in other 

62 # niceties of the SSH agent and the agent's client). 

63 'ed448': { 

64 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

65b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz 

66c2gtZWQ0NDgAAAA54vZy009Wu8wExjvEb3hqtLz1GO/+d5vmGUbErWQ4AUO9mYLT 

67zHJHc2m4s+yWzP29Cc3EcxizLG8AAAAA8BdhfCcXYXwnAAAACXNzaC1lZDQ0OAAA 

68ADni9nLTT1a7zATGO8RveGq0vPUY7/53m+YZRsStZDgBQ72ZgtPMckdzabiz7JbM 

69/b0JzcRzGLMsbwAAAAByM7GIMRvWJB3YD6SIpAF2uudX4ozZe0X917wPwiBrs373 

709TM1n94Nib6hrxGNmCk2iBQDe2KALPgA4vZy009Wu8wExjvEb3hqtLz1GO/+d5vm 

71GUbErWQ4AUO9mYLTzHJHc2m4s+yWzP29Cc3EcxizLG8AAAAAG3Rlc3Qga2V5IHdp 

72dGhvdXQgcGFzc3BocmFzZQECAwQFBgcICQ== 

73-----END OPENSSH PRIVATE KEY----- 

74''', 

75 'public_key': rb'''ssh-ed448 AAAACXNzaC1lZDQ0OAAAADni9nLTT1a7zATGO8RveGq0vPUY7/53m+YZRsStZDgBQ72ZgtPMckdzabiz7JbM/b0JzcRzGLMsbwA= test key without passphrase 

76''', 

77 'public_key_data': bytes.fromhex(''' 

78 00 00 00 09 73 73 68 2d 65 64 34 34 38 

79 00 00 00 39 

80 e2 f6 72 d3 4f 56 bb cc 04 c6 3b c4 6f 78 6a b4 

81 bc f5 18 ef fe 77 9b e6 19 46 c4 ad 64 38 01 43 

82 bd 99 82 d3 cc 72 47 73 69 b8 b3 ec 96 cc fd bd 

83 09 cd c4 73 18 b3 2c 6f 00 

84 '''), 

85 

86 'expected_signature': bytes.fromhex(''' 

87 00 00 00 09 73 73 68 2d 65 64 34 34 38 

88 00 00 00 72 06 86 

89 f4 64 a4 a6 ba d9 c3 22 c4 93 49 99 fc 11 de 67 

90 97 08 f2 d8 b7 3c 2c 13 e7 c5 1c 1e 92 a6 0e d8 

91 2f 6d 81 03 82 00 e3 72 e4 32 6d 72 d2 6d 32 84 

92 3f cc a9 1e 57 2c 00 9a b3 99 de 45 da ce 2e d1 

93 db e5 89 f3 35 be 24 58 90 c6 ca 04 f0 db 88 80 

94 db bd 77 7c 80 20 7f 3a 48 61 f6 1f ae a9 5e 53 

95 7b e0 9d 93 1e ea dc eb b5 cd 56 4c ea 8f 08 00 

96 '''), 

97 'derived_passphrase': rb'Bob0ZKSmutnDIsSTSZn8Ed5nlwjy2Lc8LBPnxRwekqYO2C9tgQOCAONy5DJtctJtMoQ/zKkeVywAmrOZ3kXazi7R2+WJ8zW+JFiQxsoE8NuIgNu9d3yAIH86SGH2H66pXlN74J2THurc67XNVkzqjwgA', 

98 }, 

99 'rsa': { 

100 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

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 

137-----END OPENSSH PRIVATE KEY----- 

138''', 

139 'public_key': rb'''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxoe7pezhxWy4NI0mUwKqg9WCYOAS+IjxN9eYcqpfcmQiojcuy9XsiN/xYJ1O94SrsKS5mEia2xHnYA4RUChTyYNcM2v6cnnBQ/N/VQhpGMN7SVxdbhKUXTWFCwbjBgO6rGyHB6WtoH8vd7TOEPt+NgcXwhsWyoaUUdYTA62V+GF9vEmxMaC4ubgDz+B0QkPnauSoNxmkhcIe0lsLNb1pClZyz88PDnKXCX/d0HuN/HJ+sbPg7dCvOyqFYSyKn3uY6bCXqoIdurxXzH3O7z0P8f5sbmKOrGGKNuNxVRbeVl/D/3uDL0nqsbfUc1qvkfwbJwtMXC4IV6kOZMSk2BAsqh7x48gQ+rhYeEVSi8F3CWs4HJQoqrGt7K9a3mCSlMBHP70u3w6ME7eumoryxlUofewTd17ZEkzdX08l2ZlKzZvwQUrc+xQZ2Uw8z2mfW6Ti4gi0pYGaig7Ke4PwuXpo/C5YAWfeXycsvJZ2uaYRjMdZeJGNAnHLUGLkBscw5aI8= test key without passphrase 

140''', 

141 'public_key_data': bytes.fromhex(''' 

142 00 00 00 07 73 73 68 2d 72 73 61 

143 00 00 00 03 01 00 01 

144 00 00 01 81 00 

145 b1 a1 ee e9 7b 38 71 5b 2e 0d 23 49 94 c0 aa a0 

146 f5 60 98 38 04 be 22 3c 4d f5 e6 1c aa 97 dc 99 

147 08 a8 8d cb b2 f5 7b 22 37 fc 58 27 53 bd e1 2a 

148 ec 29 2e 66 12 26 b6 c4 79 d8 03 84 54 0a 14 f2 

149 60 d7 0c da fe 9c 9e 70 50 fc df d5 42 1a 46 30 

150 de d2 57 17 5b 84 a5 17 4d 61 42 c1 b8 c1 80 ee 

151 ab 1b 21 c1 e9 6b 68 1f cb dd ed 33 84 3e df 8d 

152 81 c5 f0 86 c5 b2 a1 a5 14 75 84 c0 eb 65 7e 18 

153 5f 6f 12 6c 4c 68 2e 2e 6e 00 f3 f8 1d 10 90 f9 

154 da b9 2a 0d c6 69 21 70 87 b4 96 c2 cd 6f 5a 42 

155 95 9c b3 f3 c3 c3 9c a5 c2 5f f7 74 1e e3 7f 1c 

156 9f ac 6c f8 3b 74 2b ce ca a1 58 4b 22 a7 de e6 

157 3a 6c 25 ea a0 87 6e af 15 f3 1f 73 bb cf 43 fc 

158 7f 9b 1b 98 a3 ab 18 62 8d b8 dc 55 45 b7 95 97 

159 f0 ff de e0 cb d2 7a ac 6d f5 1c d6 ab e4 7f 06 

160 c9 c2 d3 17 0b 82 15 ea 43 99 31 29 36 04 0b 2a 

161 87 bc 78 f2 04 3e ae 16 1e 11 54 a2 f0 5d c2 5a 

162 ce 07 25 0a 2a ac 6b 7b 2b d6 b7 98 24 a5 30 11 

163 cf ef 4b b7 c3 a3 04 ed eb a6 a2 bc b1 95 4a 1f 

164 7b 04 dd d7 b6 44 93 37 57 d3 c9 76 66 52 b3 66 

165 fc 10 52 b7 3e c5 06 76 53 0f 33 da 67 d6 e9 38 

166 b8 82 2d 29 60 66 a2 83 b2 9e e0 fc 2e 5e 9a 3f 

167 0b 96 00 59 f7 97 c9 cb 2f 25 9d ae 69 84 63 31 

168 d6 5e 24 63 40 9c 72 d4 18 b9 01 b1 cc 39 68 8f 

169'''), 

170 'expected_signature': bytes.fromhex(''' 

171 00 00 00 07 73 73 68 2d 72 73 61 

172 00 00 01 80 

173 a2 10 7c 2e f6 bb 53 a8 74 2a a1 19 99 ad 81 be 

174 79 9c ed d6 9d 09 4e 6e c5 18 48 33 90 77 99 68 

175 f7 9e 03 5a cd 4e 18 eb 89 7d 85 a2 ee ae 4a 92 

176 f6 6f ce b9 fe 86 7f 2a 6b 31 da 6e 1a fe a2 a5 

177 88 b8 44 7f a1 76 73 b3 ec 75 b5 d0 a6 b9 15 97 

178 65 09 13 7d 94 21 d1 fb 5d 0f 8b 23 04 77 c2 c3 

179 55 22 b1 a0 09 8a f5 38 2a d6 7f 1b 87 29 a0 25 

180 d3 25 6f cb 64 61 07 98 dc 14 c5 84 f8 92 24 5e 

181 50 11 6b 49 e5 f0 cc 29 cb 29 a9 19 d8 a7 71 1f 

182 91 0b 05 b1 01 4b c2 5f 00 a5 b6 21 bf f8 2c 9d 

183 67 9b 47 3b 0a 49 6b 79 2d fc 1d ec 0c b0 e5 27 

184 22 d5 a9 f8 d3 c3 f9 df 48 68 e9 fb ef 3c dc 26 

185 bf cf ea 29 43 01 a6 e3 c5 51 95 f4 66 6d 8a 55 

186 e2 47 ec e8 30 45 4c ae 47 e7 c9 a4 21 8b 64 ba 

187 b6 88 f6 21 f8 73 b9 cb 11 a1 78 75 92 c6 5a e5 

188 64 fe ed 42 d9 95 99 e6 2b 6f 3c 16 3c 28 74 a4 

189 72 2f 0d 3f 2c 33 67 aa 35 19 8e e7 b5 11 2f b3 

190 f7 6a c5 02 e2 6f a3 42 e3 62 19 99 03 ea a5 20 

191 e7 a1 e3 bc c8 06 a3 b5 7c d6 76 5d df 6f 60 46 

192 83 2a 08 00 d6 d3 d9 a4 c1 41 8c f8 60 56 45 81 

193 da 3b a2 16 1f 9e 4e 75 83 17 da c3 53 c3 3e 19 

194 a4 1b bc d2 29 b8 78 61 2b 78 e6 b1 52 b0 d5 ec 

195 de 69 2c 48 62 d9 fd d1 9b 6b b0 49 db d3 ff 38 

196 e7 10 d9 2d ce 9f 0d 5e 09 7b 37 d2 7b c3 bf ce 

197'''), 

198 'derived_passphrase': rb'ohB8Lva7U6h0KqEZma2Bvnmc7dadCU5uxRhIM5B3mWj3ngNazU4Y64l9haLurkqS9m/Ouf6GfyprMdpuGv6ipYi4RH+hdnOz7HW10Ka5FZdlCRN9lCHR+10PiyMEd8LDVSKxoAmK9Tgq1n8bhymgJdMlb8tkYQeY3BTFhPiSJF5QEWtJ5fDMKcspqRnYp3EfkQsFsQFLwl8ApbYhv/gsnWebRzsKSWt5Lfwd7Ayw5Sci1an408P530ho6fvvPNwmv8/qKUMBpuPFUZX0Zm2KVeJH7OgwRUyuR+fJpCGLZLq2iPYh+HO5yxGheHWSxlrlZP7tQtmVmeYrbzwWPCh0pHIvDT8sM2eqNRmO57URL7P3asUC4m+jQuNiGZkD6qUg56HjvMgGo7V81nZd329gRoMqCADW09mkwUGM+GBWRYHaO6IWH55OdYMX2sNTwz4ZpBu80im4eGEreOaxUrDV7N5pLEhi2f3Rm2uwSdvT/zjnENktzp8NXgl7N9J7w7/O', 

199 }, 

200} 

201 

202UNSUITABLE_KEYS: Mapping[str, SSHTestKey] = { 

203 'dsa1024': { 

204 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

205b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH 

206NzAAAAgQC7KAZXqBGNVLBQPrcMYAoNW54BhD8aIhe7BDWYzJcsaMt72VKSkguZ8+XR7nRa 

2070C/ZsBi+uJp0dpxy9ZMTOWX4u5YPMeQcXEdGExZIfimGqSOAsy6fCld2IfJZJZExcCmhe9 

208Ssjsd3YSAPJRluOXFQc95MZoR5hMwlIDD8QzrE7QAAABUA99nOZOgd7aHMVGoXpUEBcn7H 

209ossAAACALr2Ag3hxM3rKdxzVUw8fX0VVPXO+3+Kr8hGe0Kc/7NwVaBVL1GQ8fenBuWynpA 

210UbH0wo3h1wkB/8hX6p+S8cnu5rIBlUuVNwLw/bIYohK98LfqTYK/V+g6KD+8m34wvEiXZm 

211qywY54n2bksch1Nqvj/tNpLzExSx/XS0kSM1aigAAACAbQNRPcVEuGDrEcf+xg5tgAejPX 

212BPXr/Jss+Chk64km3mirMYjAWyWYtVcgT+7hOYxtYRin8LyMLqKRmqa0Q5UrvDfChgLhvs 

213G9YSb/Mpw5qm8PiHSafwhkaz/te3+8hKogqoe7sd+tCF06IpJr5k70ACiNtRGqssNF8Elr 

214l1efYAAAH4swlfVrMJX1YAAAAHc3NoLWRzcwAAAIEAuygGV6gRjVSwUD63DGAKDVueAYQ/ 

215GiIXuwQ1mMyXLGjLe9lSkpILmfPl0e50WtAv2bAYvriadHaccvWTEzll+LuWDzHkHFxHRh 

216MWSH4phqkjgLMunwpXdiHyWSWRMXApoXvUrI7Hd2EgDyUZbjlxUHPeTGaEeYTMJSAw/EM6 

217xO0AAAAVAPfZzmToHe2hzFRqF6VBAXJ+x6LLAAAAgC69gIN4cTN6yncc1VMPH19FVT1zvt 

218/iq/IRntCnP+zcFWgVS9RkPH3pwblsp6QFGx9MKN4dcJAf/IV+qfkvHJ7uayAZVLlTcC8P 

2192yGKISvfC36k2Cv1foOig/vJt+MLxIl2ZqssGOeJ9m5LHIdTar4/7TaS8xMUsf10tJEjNW 

220ooAAAAgG0DUT3FRLhg6xHH/sYObYAHoz1wT16/ybLPgoZOuJJt5oqzGIwFslmLVXIE/u4T 

221mMbWEYp/C8jC6ikZqmtEOVK7w3woYC4b7BvWEm/zKcOapvD4h0mn8IZGs/7Xt/vISqIKqH 

222u7HfrQhdOiKSa+ZO9AAojbURqrLDRfBJa5dXn2AAAAFQDJHfenj4EJ9WkehpdJatPBlqCW 

2230gAAABt0ZXN0IGtleSB3aXRob3V0IHBhc3NwaHJhc2UBAgMEBQYH 

224-----END OPENSSH PRIVATE KEY----- 

225''', 

226 'public_key': rb'''ssh-dss AAAAB3NzaC1kc3MAAACBALsoBleoEY1UsFA+twxgCg1bngGEPxoiF7sENZjMlyxoy3vZUpKSC5nz5dHudFrQL9mwGL64mnR2nHL1kxM5Zfi7lg8x5BxcR0YTFkh+KYapI4CzLp8KV3Yh8lklkTFwKaF71KyOx3dhIA8lGW45cVBz3kxmhHmEzCUgMPxDOsTtAAAAFQD32c5k6B3tocxUahelQQFyfseiywAAAIAuvYCDeHEzesp3HNVTDx9fRVU9c77f4qvyEZ7Qpz/s3BVoFUvUZDx96cG5bKekBRsfTCjeHXCQH/yFfqn5Lxye7msgGVS5U3AvD9shiiEr3wt+pNgr9X6DooP7ybfjC8SJdmarLBjnifZuSxyHU2q+P+02kvMTFLH9dLSRIzVqKAAAAIBtA1E9xUS4YOsRx/7GDm2AB6M9cE9ev8myz4KGTriSbeaKsxiMBbJZi1VyBP7uE5jG1hGKfwvIwuopGaprRDlSu8N8KGAuG+wb1hJv8ynDmqbw+IdJp/CGRrP+17f7yEqiCqh7ux360IXToikmvmTvQAKI21Eaqyw0XwSWuXV59g== test key without passphrase 

227''', 

228 'public_key_data': bytes.fromhex(''' 

229 00 00 00 07 73 73 68 2d 64 73 73 

230 00 00 00 81 00 

231 bb 28 06 57 a8 11 8d 54 b0 50 3e b7 0c 60 0a 0d 

232 5b 9e 01 84 3f 1a 22 17 bb 04 35 98 cc 97 2c 68 

233 cb 7b d9 52 92 92 0b 99 f3 e5 d1 ee 74 5a d0 2f 

234 d9 b0 18 be b8 9a 74 76 9c 72 f5 93 13 39 65 f8 

235 bb 96 0f 31 e4 1c 5c 47 46 13 16 48 7e 29 86 a9 

236 23 80 b3 2e 9f 0a 57 76 21 f2 59 25 91 31 70 29 

237 a1 7b d4 ac 8e c7 77 61 20 0f 25 19 6e 39 71 50 

238 73 de 4c 66 84 79 84 cc 25 20 30 fc 43 3a c4 ed 

239 00 00 00 15 00 f7 d9 ce 64 

240 e8 1d ed a1 cc 54 6a 17 a5 41 01 72 7e c7 a2 cb 

241 00 00 00 80 

242 2e bd 80 83 78 71 33 7a ca 77 1c d5 53 0f 1f 5f 

243 45 55 3d 73 be df e2 ab f2 11 9e d0 a7 3f ec dc 

244 15 68 15 4b d4 64 3c 7d e9 c1 b9 6c a7 a4 05 1b 

245 1f 4c 28 de 1d 70 90 1f fc 85 7e a9 f9 2f 1c 9e 

246 ee 6b 20 19 54 b9 53 70 2f 0f db 21 8a 21 2b df 

247 0b 7e a4 d8 2b f5 7e 83 a2 83 fb c9 b7 e3 0b c4 

248 89 76 66 ab 2c 18 e7 89 f6 6e 4b 1c 87 53 6a be 

249 3f ed 36 92 f3 13 14 b1 fd 74 b4 91 23 35 6a 28 

250 00 00 00 80 

251 6d 03 51 3d c5 44 b8 60 eb 11 c7 fe c6 0e 6d 80 

252 07 a3 3d 70 4f 5e bf c9 b2 cf 82 86 4e b8 92 6d 

253 e6 8a b3 18 8c 05 b2 59 8b 55 72 04 fe ee 13 98 

254 c6 d6 11 8a 7f 0b c8 c2 ea 29 19 aa 6b 44 39 52 

255 bb c3 7c 28 60 2e 1b ec 1b d6 12 6f f3 29 c3 9a 

256 a6 f0 f8 87 49 a7 f0 86 46 b3 fe d7 b7 fb c8 4a 

257 a2 0a a8 7b bb 1d fa d0 85 d3 a2 29 26 be 64 ef 

258 40 02 88 db 51 1a ab 2c 34 5f 04 96 b9 75 79 f6 

259'''), 

260 'expected_signature': None, 

261 'derived_passphrase': None, 

262 }, 

263 'ecdsa256': { 

264 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

265b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS 

2661zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTLbU0zDwsk2Dvp+VYIrsNVf5gWwz2S 

2673SZ8TbxiQRkpnGSVqyIoHJOJc+NQItAa7xlJ/8Z6gfz57Z3apUkaMJm6AAAAuKeY+YinmP 

268mIAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMttTTMPCyTYO+n5 

269Vgiuw1V/mBbDPZLdJnxNvGJBGSmcZJWrIigck4lz41Ai0BrvGUn/xnqB/PntndqlSRowmb 

270oAAAAhAKIl/3n0pKVIxpZkXTGtii782Qr4yIcvHdpxjO/QsIqKAAAAG3Rlc3Qga2V5IHdp 

271dGhvdXQgcGFzc3BocmFzZQECAwQ= 

272-----END OPENSSH PRIVATE KEY----- 

273''', 

274 'public_key': rb'''ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMttTTMPCyTYO+n5Vgiuw1V/mBbDPZLdJnxNvGJBGSmcZJWrIigck4lz41Ai0BrvGUn/xnqB/PntndqlSRowmbo= test key without passphrase 

275''', 

276 'public_key_data': bytes.fromhex(''' 

277 00 00 00 13 65 63 64 73 61 2d 73 68 61 32 2d 6e 

278 69 73 74 70 32 35 36 

279 00 00 00 08 6e 69 73 74 70 32 35 36 

280 00 00 00 41 04 

281 cb 6d 4d 33 0f 0b 24 d8 3b e9 f9 56 08 ae c3 55 

282 7f 98 16 c3 3d 92 dd 26 7c 4d bc 62 41 19 29 9c 

283 64 95 ab 22 28 1c 93 89 73 e3 50 22 d0 1a ef 19 

284 49 ff c6 7a 81 fc f9 ed 9d da a5 49 1a 30 99 ba 

285'''), 

286 'expected_signature': None, 

287 'derived_passphrase': None, 

288 }, 

289 'ecdsa384': { 

290 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- 

291b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS 

2921zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQSgkOjkAvq7v5vHuj3KBL4/EAWcn5hZ 

293DyKcbyV0eBMGFq7hKXQlZqIahLVqeMR0QqmkxNJ2rly2VHcXneq3vZ+9fIsWCOdYk5WP3N 

294ZPzv911Xn7wbEkC7QndD5zKlm4pBUAAADomhj+IZoY/iEAAAATZWNkc2Etc2hhMi1uaXN0 

295cDM4NAAAAAhuaXN0cDM4NAAAAGEEoJDo5AL6u7+bx7o9ygS+PxAFnJ+YWQ8inG8ldHgTBh 

296au4Sl0JWaiGoS1anjEdEKppMTSdq5ctlR3F53qt72fvXyLFgjnWJOVj9zWT87/ddV5+8Gx 

297JAu0J3Q+cypZuKQVAAAAMQD5sTy8p+B1cn/DhOmXquui1BcxvASqzzevkBlbQoBa73y04B 

2982OdqVOVRkwZWRROz0AAAAbdGVzdCBrZXkgd2l0aG91dCBwYXNzcGhyYXNlAQIDBA== 

299-----END OPENSSH PRIVATE KEY----- 

300''', 

301 'public_key': rb'''ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBKCQ6OQC+ru/m8e6PcoEvj8QBZyfmFkPIpxvJXR4EwYWruEpdCVmohqEtWp4xHRCqaTE0nauXLZUdxed6re9n718ixYI51iTlY/c1k/O/3XVefvBsSQLtCd0PnMqWbikFQ== test key without passphrase 

302''', 

303 'public_key_data': bytes.fromhex(''' 

304 00 00 00 13 

305 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70 

306 33 38 34 

307 00 00 00 08 6e 69 73 74 70 33 38 34 

308 00 00 00 61 04 

309 a0 90 e8 e4 02 fa bb bf 9b c7 ba 3d ca 04 be 3f 

310 10 05 9c 9f 98 59 0f 22 9c 6f 25 74 78 13 06 16 

311 ae e1 29 74 25 66 a2 1a 84 b5 6a 78 c4 74 42 a9 

312 a4 c4 d2 76 ae 5c b6 54 77 17 9d ea b7 bd 9f bd 

313 7c 8b 16 08 e7 58 93 95 8f dc d6 4f ce ff 75 d5 

314 79 fb c1 b1 24 0b b4 27 74 3e 73 2a 59 b8 a4 15 

315'''), 

316 'expected_signature': None, 

317 'derived_passphrase': None, 

318 }, 

319} 

320 

321DUMMY_SERVICE = 'service1' 

322DUMMY_PASSPHRASE = b'my secret passphrase\n' 

323DUMMY_KEY1 = SUPPORTED_KEYS['ed25519']['public_key_data'] 

324DUMMY_KEY1_B64 = base64.standard_b64encode(DUMMY_KEY1).decode('ASCII') 

325DUMMY_KEY2 = SUPPORTED_KEYS['rsa']['public_key_data'] 

326DUMMY_KEY2_B64 = base64.standard_b64encode(DUMMY_KEY2).decode('ASCII') 

327DUMMY_CONFIG_SETTINGS = {"length": 10, "upper": 1, "lower": 1, "repeat": 5, 

328 "number": 1, "space": 1, "dash": 1, "symbol": 1} 

329DUMMY_RESULT_PASSPHRASE = b'.2V_QJkd o' 

330DUMMY_RESULT_KEY1 = b'E<b<{ -7iG' 

331DUMMY_PHRASE_FROM_KEY1_RAW = ( 

332 b'\x00\x00\x00\x0bssh-ed25519' 

333 b'\x00\x00\x00@\xf0\x98\x19\x80l\x1a\x97\xd5&\x03n' 

334 b'\xcc\xe3e\x8f\x86f\x07\x13\x19\x13\t!33\xf9\xe46S' 

335 b'\x1d\xaf\xfd\r\x08\x1f\xec\xf8s\x9b\x8c_U9\x16|ST,' 

336 b'\x1eR\xbb0\xed\x7f\x89\xe2/iQU\xd8\x9e\xa6\x02' 

337) 

338DUMMY_PHRASE_FROM_KEY1 = b'8JgZgGwal9UmA27M42WPhmYHExkTCSEzM/nkNlMdr/0NCB/s+HObjF9VORZ8U1QsHlK7MO1/ieIvaVFV2J6mAg==' 

339 

340skip_if_no_agent = pytest.mark.skipif( 

341 not os.environ.get('SSH_AUTH_SOCK'), reason='running SSH agent required') 

342 

343def list_keys( 

344 self: Any = None, 

345) -> list[ssh_agent_client.types.KeyCommentPair]: 

346 Pair = ssh_agent_client.types.KeyCommentPair 

347 list1 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII')) 

348 for key, value in SUPPORTED_KEYS.items()] 

349 list2 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII')) 

350 for key, value in UNSUITABLE_KEYS.items()] 

351 return list1 + list2 

352 

353def list_keys_singleton( 

354 self: Any = None, 

355) -> list[ssh_agent_client.types.KeyCommentPair]: 

356 Pair = ssh_agent_client.types.KeyCommentPair 

357 list1 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII')) 

358 for key, value in SUPPORTED_KEYS.items()] 

359 return list1[:1] 

360 

361def suitable_ssh_keys( 

362 conn: Any 

363) -> Iterator[ssh_agent_client.types.KeyCommentPair]: 

364 yield from [ 

365 ssh_agent_client.types.KeyCommentPair(DUMMY_KEY1, b'no comment'), 

366 ssh_agent_client.types.KeyCommentPair(DUMMY_KEY2, b'a comment'), 

367 ] 

368 

369def phrase_from_key(key: bytes) -> bytes: 

370 if key == DUMMY_KEY1: # pragma: no branch 

371 return DUMMY_PHRASE_FROM_KEY1 

372 raise KeyError(key) # pragma: no cover 

373 

374@contextlib.contextmanager 

375def isolated_config( 

376 monkeypatch: Any, runner: click.testing.CliRunner, config: Any, 

377): 

378 prog_name = derivepassphrase.cli.prog_name 

379 env_name = prog_name.replace(' ', '_').upper() + '_PATH' 

380 with runner.isolated_filesystem(): 

381 monkeypatch.setenv('HOME', os.getcwd()) 

382 monkeypatch.setenv('USERPROFILE', os.getcwd()) 

383 monkeypatch.delenv(env_name, raising=False) 

384 os.makedirs(os.path.dirname(derivepassphrase.cli._config_filename()), 

385 exist_ok=True) 

386 with open(derivepassphrase.cli._config_filename(), 'wt') as outfile: 

387 json.dump(config, outfile) 

388 yield 

389 

390def auto_prompt(*args: Any, **kwargs: Any) -> str: 

391 return DUMMY_PASSPHRASE.decode('UTF-8')