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 package org.eclipse.jgit.transport;
45
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.OutputStream;
49 import java.net.HttpURLConnection;
50 import java.security.InvalidAlgorithmParameterException;
51 import java.security.InvalidKeyException;
52 import java.security.NoSuchAlgorithmException;
53 import java.security.spec.InvalidKeySpecException;
54 import java.text.MessageFormat;
55
56 import javax.crypto.Cipher;
57 import javax.crypto.CipherInputStream;
58 import javax.crypto.CipherOutputStream;
59 import javax.crypto.NoSuchPaddingException;
60 import javax.crypto.SecretKey;
61 import javax.crypto.SecretKeyFactory;
62 import javax.crypto.spec.PBEKeySpec;
63 import javax.crypto.spec.PBEParameterSpec;
64
65 import org.eclipse.jgit.internal.JGitText;
66
67 abstract class WalkEncryption {
68 static final WalkEncryption NONE = new NoEncryption();
69
70 static final String JETS3T_CRYPTO_VER = "jets3t-crypto-ver";
71
72 static final String JETS3T_CRYPTO_ALG = "jets3t-crypto-alg";
73
74 abstract OutputStream encrypt(OutputStream os) throws IOException;
75
76 abstract InputStream decrypt(InputStream in) throws IOException;
77
78 abstract void request(HttpURLConnection u, String prefix);
79
80 abstract void validate(HttpURLConnection u, String p) throws IOException;
81
82 protected void validateImpl(final HttpURLConnection u, final String p,
83 final String version, final String name) throws IOException {
84 String v;
85
86 v = u.getHeaderField(p + JETS3T_CRYPTO_VER);
87 if (v == null)
88 v = "";
89 if (!version.equals(v))
90 throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionVersion, v));
91
92 v = u.getHeaderField(p + JETS3T_CRYPTO_ALG);
93 if (v == null)
94 v = "";
95 if (!name.equals(v))
96 throw new IOException(JGitText.get().unsupportedEncryptionAlgorithm + v);
97 }
98
99 IOException error(final Throwable why) {
100 final IOException e;
101 e = new IOException(MessageFormat.format(JGitText.get().encryptionError, why.getMessage()));
102 e.initCause(why);
103 return e;
104 }
105
106 private static class NoEncryption extends WalkEncryption {
107 @Override
108 void request(HttpURLConnection u, String prefix) {
109
110 }
111
112 @Override
113 void validate(final HttpURLConnection u, final String p)
114 throws IOException {
115 validateImpl(u, p, "", "");
116 }
117
118 @Override
119 InputStream decrypt(InputStream in) {
120 return in;
121 }
122
123 @Override
124 OutputStream encrypt(OutputStream os) {
125 return os;
126 }
127 }
128
129 static class ObjectEncryptionV2 extends WalkEncryption {
130 private static int ITERATION_COUNT = 5000;
131
132 private static byte[] salt = { (byte) 0xA4, (byte) 0x0B, (byte) 0xC8,
133 (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 };
134
135 private final String algorithmName;
136
137 private final SecretKey skey;
138
139 private final PBEParameterSpec aspec;
140
141 ObjectEncryptionV2(final String algo, final String key)
142 throws InvalidKeySpecException, NoSuchAlgorithmException {
143 algorithmName = algo;
144
145 final PBEKeySpec s;
146 s = new PBEKeySpec(key.toCharArray(), salt, ITERATION_COUNT, 32);
147 skey = SecretKeyFactory.getInstance(algo).generateSecret(s);
148 aspec = new PBEParameterSpec(salt, ITERATION_COUNT);
149 }
150
151 @Override
152 void request(final HttpURLConnection u, final String prefix) {
153 u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, "2");
154 u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, algorithmName);
155 }
156
157 @Override
158 void validate(final HttpURLConnection u, final String p)
159 throws IOException {
160 validateImpl(u, p, "2", algorithmName);
161 }
162
163 @Override
164 OutputStream encrypt(final OutputStream os) throws IOException {
165 try {
166 final Cipher c = Cipher.getInstance(algorithmName);
167 c.init(Cipher.ENCRYPT_MODE, skey, aspec);
168 return new CipherOutputStream(os, c);
169 } catch (NoSuchAlgorithmException e) {
170 throw error(e);
171 } catch (NoSuchPaddingException e) {
172 throw error(e);
173 } catch (InvalidKeyException e) {
174 throw error(e);
175 } catch (InvalidAlgorithmParameterException e) {
176 throw error(e);
177 }
178 }
179
180 @Override
181 InputStream decrypt(final InputStream in) throws IOException {
182 try {
183 final Cipher c = Cipher.getInstance(algorithmName);
184 c.init(Cipher.DECRYPT_MODE, skey, aspec);
185 return new CipherInputStream(in, c);
186 } catch (NoSuchAlgorithmException e) {
187 throw error(e);
188 } catch (NoSuchPaddingException e) {
189 throw error(e);
190 } catch (InvalidKeyException e) {
191 throw error(e);
192 } catch (InvalidAlgorithmParameterException e) {
193 throw error(e);
194 }
195 }
196 }
197 }