You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WalkEncryption.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*
  2. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.transport;
  44. import java.io.IOException;
  45. import java.io.InputStream;
  46. import java.io.OutputStream;
  47. import java.net.HttpURLConnection;
  48. import java.security.AlgorithmParameters;
  49. import java.security.GeneralSecurityException;
  50. import java.security.spec.AlgorithmParameterSpec;
  51. import java.security.spec.KeySpec;
  52. import java.text.MessageFormat;
  53. import java.util.Locale;
  54. import java.util.Properties;
  55. import java.util.regex.Matcher;
  56. import java.util.regex.Pattern;
  57. import javax.crypto.Cipher;
  58. import javax.crypto.CipherInputStream;
  59. import javax.crypto.CipherOutputStream;
  60. import javax.crypto.SecretKey;
  61. import javax.crypto.SecretKeyFactory;
  62. import javax.crypto.spec.IvParameterSpec;
  63. import javax.crypto.spec.PBEKeySpec;
  64. import javax.crypto.spec.PBEParameterSpec;
  65. import javax.crypto.spec.SecretKeySpec;
  66. import javax.xml.bind.DatatypeConverter;
  67. import org.eclipse.jgit.internal.JGitText;
  68. import org.eclipse.jgit.util.Base64;
  69. abstract class WalkEncryption {
  70. static final WalkEncryption NONE = new NoEncryption();
  71. static final String JETS3T_CRYPTO_VER = "jets3t-crypto-ver"; //$NON-NLS-1$
  72. static final String JETS3T_CRYPTO_ALG = "jets3t-crypto-alg"; //$NON-NLS-1$
  73. // Note: encrypt -> request state machine, step 1.
  74. abstract OutputStream encrypt(OutputStream output) throws IOException;
  75. // Note: encrypt -> request state machine, step 2.
  76. abstract void request(HttpURLConnection conn, String prefix) throws IOException;
  77. // Note: validate -> decrypt state machine, step 1.
  78. abstract void validate(HttpURLConnection conn, String prefix) throws IOException;
  79. // Note: validate -> decrypt state machine, step 2.
  80. abstract InputStream decrypt(InputStream input) throws IOException;
  81. // TODO mixed ciphers
  82. // consider permitting mixed ciphers to facilitate algorithm migration
  83. // i.e. user keeps the password, but changes the algorithm
  84. // then existing remote entries will still be readable
  85. /**
  86. * Validate
  87. *
  88. * @param u
  89. * a {@link java.net.HttpURLConnection} object.
  90. * @param prefix
  91. * a {@link java.lang.String} object.
  92. * @param version
  93. * a {@link java.lang.String} object.
  94. * @param name
  95. * a {@link java.lang.String} object.
  96. * @throws java.io.IOException
  97. * if any.
  98. */
  99. protected void validateImpl(final HttpURLConnection u, final String prefix,
  100. final String version, final String name) throws IOException {
  101. String v;
  102. v = u.getHeaderField(prefix + JETS3T_CRYPTO_VER);
  103. if (v == null)
  104. v = ""; //$NON-NLS-1$
  105. if (!version.equals(v))
  106. throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionVersion, v));
  107. v = u.getHeaderField(prefix + JETS3T_CRYPTO_ALG);
  108. if (v == null)
  109. v = ""; //$NON-NLS-1$
  110. // Standard names are not case-sensitive.
  111. // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
  112. if (!name.equalsIgnoreCase(v))
  113. throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionAlgorithm, v));
  114. }
  115. IOException error(Throwable why) {
  116. return new IOException(MessageFormat
  117. .format(JGitText.get().encryptionError,
  118. why.getMessage()), why);
  119. }
  120. private static class NoEncryption extends WalkEncryption {
  121. @Override
  122. void request(HttpURLConnection u, String prefix) {
  123. // Don't store any request properties.
  124. }
  125. @Override
  126. void validate(HttpURLConnection u, String prefix)
  127. throws IOException {
  128. validateImpl(u, prefix, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
  129. }
  130. @Override
  131. InputStream decrypt(InputStream in) {
  132. return in;
  133. }
  134. @Override
  135. OutputStream encrypt(OutputStream os) {
  136. return os;
  137. }
  138. }
  139. /**
  140. * JetS3t compatibility reference: <a href=
  141. * "https://bitbucket.org/jmurty/jets3t/src/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java">
  142. * EncryptionUtil.java</a>
  143. * <p>
  144. * Note: EncryptionUtil is inadequate:
  145. * <li>EncryptionUtil.isCipherAvailableForUse checks encryption only which
  146. * "always works", but in JetS3t both encryption and decryption use non-IV
  147. * aware algorithm parameters for all PBE specs, which breaks in case of AES
  148. * <li>that means that only non-IV algorithms will work round trip in
  149. * JetS3t, such as PBEWithMD5AndDES and PBEWithSHAAndTwofish-CBC
  150. * <li>any AES based algorithms such as "PBE...With...And...AES" will not
  151. * work, since they need proper IV setup
  152. */
  153. static class JetS3tV2 extends WalkEncryption {
  154. static final String VERSION = "2"; //$NON-NLS-1$
  155. static final String ALGORITHM = "PBEWithMD5AndDES"; //$NON-NLS-1$
  156. static final int ITERATIONS = 5000;
  157. static final int KEY_SIZE = 32;
  158. static final byte[] SALT = { //
  159. (byte) 0xA4, (byte) 0x0B, (byte) 0xC8, (byte) 0x34, //
  160. (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 //
  161. };
  162. // Size 16, see com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE
  163. static final byte[] ZERO_AES_IV = new byte[16];
  164. private static final String CRYPTO_VER = VERSION;
  165. private final String cryptoAlg;
  166. private final SecretKey secretKey;
  167. private final AlgorithmParameterSpec paramSpec;
  168. JetS3tV2(final String algo, final String key)
  169. throws GeneralSecurityException {
  170. cryptoAlg = algo;
  171. // Verify if cipher is present.
  172. Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  173. // Standard names are not case-sensitive.
  174. // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
  175. String cryptoName = cryptoAlg.toUpperCase(Locale.ROOT);
  176. if (!cryptoName.startsWith("PBE")) //$NON-NLS-1$
  177. throw new GeneralSecurityException(JGitText.get().encryptionOnlyPBE);
  178. PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
  179. secretKey = SecretKeyFactory.getInstance(algo).generateSecret(keySpec);
  180. // Detect algorithms which require initialization vector.
  181. boolean useIV = cryptoName.contains("AES"); //$NON-NLS-1$
  182. // PBEParameterSpec algorithm parameters are supported from Java 8.
  183. if (useIV) {
  184. // Support IV where possible:
  185. // * since JCE provider uses random IV for PBE/AES
  186. // * and there is no place to store dynamic IV in JetS3t V2
  187. // * we use static IV, and tolerate increased security risk
  188. // TODO back port this change to JetS3t V2
  189. // See:
  190. // https://bitbucket.org/jmurty/jets3t/raw/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java
  191. // http://cr.openjdk.java.net/~mullan/webrevs/ascarpin/webrev.00/raw_files/new/src/share/classes/com/sun/crypto/provider/PBES2Core.java
  192. IvParameterSpec paramIV = new IvParameterSpec(ZERO_AES_IV);
  193. paramSpec = new PBEParameterSpec(SALT, ITERATIONS, paramIV);
  194. } else {
  195. // Strict legacy JetS3t V2 compatibility, with no IV support.
  196. paramSpec = new PBEParameterSpec(SALT, ITERATIONS);
  197. }
  198. // Verify if cipher + key are allowed by policy.
  199. cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
  200. cipher.doFinal();
  201. }
  202. @Override
  203. void request(HttpURLConnection u, String prefix) {
  204. u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, CRYPTO_VER);
  205. u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, cryptoAlg);
  206. }
  207. @Override
  208. void validate(HttpURLConnection u, String prefix)
  209. throws IOException {
  210. validateImpl(u, prefix, CRYPTO_VER, cryptoAlg);
  211. }
  212. @Override
  213. OutputStream encrypt(OutputStream os) throws IOException {
  214. try {
  215. final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  216. cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
  217. return new CipherOutputStream(os, cipher);
  218. } catch (GeneralSecurityException e) {
  219. throw error(e);
  220. }
  221. }
  222. @Override
  223. InputStream decrypt(InputStream in) throws IOException {
  224. try {
  225. final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  226. cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
  227. return new CipherInputStream(in, cipher);
  228. } catch (GeneralSecurityException e) {
  229. throw error(e);
  230. }
  231. }
  232. }
  233. /** Encryption property names. */
  234. interface Keys {
  235. // Remote S3 meta: V1 algorithm name or V2 profile name.
  236. String JGIT_PROFILE = "jgit-crypto-profile"; //$NON-NLS-1$
  237. // Remote S3 meta: JGit encryption implementation version.
  238. String JGIT_VERSION = "jgit-crypto-version"; //$NON-NLS-1$
  239. // Remote S3 meta: base-64 encoded cipher algorithm parameters.
  240. String JGIT_CONTEXT = "jgit-crypto-context"; //$NON-NLS-1$
  241. // Amazon S3 connection configuration file profile property suffixes:
  242. String X_ALGO = ".algo"; //$NON-NLS-1$
  243. String X_KEY_ALGO = ".key.algo"; //$NON-NLS-1$
  244. String X_KEY_SIZE = ".key.size"; //$NON-NLS-1$
  245. String X_KEY_ITER = ".key.iter"; //$NON-NLS-1$
  246. String X_KEY_SALT = ".key.salt"; //$NON-NLS-1$
  247. }
  248. /** Encryption constants and defaults. */
  249. interface Vals {
  250. // Compatibility defaults.
  251. String DEFAULT_VERS = "0"; //$NON-NLS-1$
  252. String DEFAULT_ALGO = JetS3tV2.ALGORITHM;
  253. String DEFAULT_KEY_ALGO = JetS3tV2.ALGORITHM;
  254. String DEFAULT_KEY_SIZE = Integer.toString(JetS3tV2.KEY_SIZE);
  255. String DEFAULT_KEY_ITER = Integer.toString(JetS3tV2.ITERATIONS);
  256. String DEFAULT_KEY_SALT = DatatypeConverter.printHexBinary(JetS3tV2.SALT);
  257. String EMPTY = ""; //$NON-NLS-1$
  258. // Match white space.
  259. String REGEX_WS = "\\s+"; //$NON-NLS-1$
  260. // Match PBE ciphers, i.e: PBEWithMD5AndDES
  261. String REGEX_PBE = "(PBE).*(WITH).+(AND).+"; //$NON-NLS-1$
  262. // Match transformation ciphers, i.e: AES/CBC/PKCS5Padding
  263. String REGEX_TRANS = "(.+)/(.+)/(.+)"; //$NON-NLS-1$
  264. }
  265. static GeneralSecurityException securityError(String message) {
  266. return new GeneralSecurityException(
  267. MessageFormat.format(JGitText.get().encryptionError, message));
  268. }
  269. /**
  270. * Base implementation of JGit symmetric encryption. Supports V2 properties
  271. * format.
  272. */
  273. static abstract class SymmetricEncryption extends WalkEncryption
  274. implements Keys, Vals {
  275. /** Encryption profile, root name of group of related properties. */
  276. final String profile;
  277. /** Encryption version, reflects actual implementation class. */
  278. final String version;
  279. /** Full cipher algorithm name. */
  280. final String cipherAlgo;
  281. /** Cipher algorithm name for parameters lookup. */
  282. final String paramsAlgo;
  283. /** Generated secret key. */
  284. final SecretKey secretKey;
  285. SymmetricEncryption(Properties props) throws GeneralSecurityException {
  286. profile = props.getProperty(AmazonS3.Keys.CRYPTO_ALG);
  287. version = props.getProperty(AmazonS3.Keys.CRYPTO_VER);
  288. String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
  289. cipherAlgo = props.getProperty(profile + X_ALGO, DEFAULT_ALGO);
  290. String keyAlgo = props.getProperty(profile + X_KEY_ALGO, DEFAULT_KEY_ALGO);
  291. String keySize = props.getProperty(profile + X_KEY_SIZE, DEFAULT_KEY_SIZE);
  292. String keyIter = props.getProperty(profile + X_KEY_ITER, DEFAULT_KEY_ITER);
  293. String keySalt = props.getProperty(profile + X_KEY_SALT, DEFAULT_KEY_SALT);
  294. // Verify if cipher is present.
  295. Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
  296. // Verify if key factory is present.
  297. SecretKeyFactory factory = SecretKeyFactory.getInstance(keyAlgo);
  298. final int size;
  299. try {
  300. size = Integer.parseInt(keySize);
  301. } catch (Exception e) {
  302. throw securityError(X_KEY_SIZE + EMPTY + keySize);
  303. }
  304. final int iter;
  305. try {
  306. iter = Integer.parseInt(keyIter);
  307. } catch (Exception e) {
  308. throw securityError(X_KEY_ITER + EMPTY + keyIter);
  309. }
  310. final byte[] salt;
  311. try {
  312. salt = DatatypeConverter
  313. .parseHexBinary(keySalt.replaceAll(REGEX_WS, EMPTY));
  314. } catch (Exception e) {
  315. throw securityError(X_KEY_SALT + EMPTY + keySalt);
  316. }
  317. KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iter, size);
  318. SecretKey keyBase = factory.generateSecret(keySpec);
  319. String name = cipherAlgo.toUpperCase(Locale.ROOT);
  320. Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
  321. Matcher matcherTrans = Pattern.compile(REGEX_TRANS).matcher(name);
  322. if (matcherPBE.matches()) {
  323. paramsAlgo = cipherAlgo;
  324. secretKey = keyBase;
  325. } else if (matcherTrans.find()) {
  326. paramsAlgo = matcherTrans.group(1);
  327. secretKey = new SecretKeySpec(keyBase.getEncoded(), paramsAlgo);
  328. } else {
  329. throw new GeneralSecurityException(MessageFormat.format(
  330. JGitText.get().unsupportedEncryptionAlgorithm,
  331. cipherAlgo));
  332. }
  333. // Verify if cipher + key are allowed by policy.
  334. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  335. cipher.doFinal();
  336. }
  337. // Shared state encrypt -> request.
  338. volatile String context;
  339. @Override
  340. OutputStream encrypt(OutputStream output) throws IOException {
  341. try {
  342. Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
  343. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  344. AlgorithmParameters params = cipher.getParameters();
  345. if (params == null) {
  346. context = EMPTY;
  347. } else {
  348. context = Base64.encodeBytes(params.getEncoded());
  349. }
  350. return new CipherOutputStream(output, cipher);
  351. } catch (Exception e) {
  352. throw error(e);
  353. }
  354. }
  355. @Override
  356. void request(HttpURLConnection conn, String prefix) throws IOException {
  357. conn.setRequestProperty(prefix + JGIT_PROFILE, profile);
  358. conn.setRequestProperty(prefix + JGIT_VERSION, version);
  359. conn.setRequestProperty(prefix + JGIT_CONTEXT, context);
  360. // No cleanup:
  361. // single encrypt can be followed by several request
  362. // from the AmazonS3.putImpl() multiple retry attempts
  363. // context = null; // Cleanup encrypt -> request transition.
  364. // TODO re-factor AmazonS3.putImpl to be more transaction-like
  365. }
  366. // Shared state validate -> decrypt.
  367. volatile Cipher decryptCipher;
  368. @Override
  369. void validate(HttpURLConnection conn, String prefix)
  370. throws IOException {
  371. String prof = conn.getHeaderField(prefix + JGIT_PROFILE);
  372. String vers = conn.getHeaderField(prefix + JGIT_VERSION);
  373. String cont = conn.getHeaderField(prefix + JGIT_CONTEXT);
  374. if (prof == null) {
  375. throw new IOException(MessageFormat
  376. .format(JGitText.get().encryptionError, JGIT_PROFILE));
  377. }
  378. if (vers == null) {
  379. throw new IOException(MessageFormat
  380. .format(JGitText.get().encryptionError, JGIT_VERSION));
  381. }
  382. if (cont == null) {
  383. throw new IOException(MessageFormat
  384. .format(JGitText.get().encryptionError, JGIT_CONTEXT));
  385. }
  386. if (!profile.equals(prof)) {
  387. throw new IOException(MessageFormat.format(
  388. JGitText.get().unsupportedEncryptionAlgorithm, prof));
  389. }
  390. if (!version.equals(vers)) {
  391. throw new IOException(MessageFormat.format(
  392. JGitText.get().unsupportedEncryptionVersion, vers));
  393. }
  394. try {
  395. decryptCipher = InsecureCipherFactory.create(cipherAlgo);
  396. if (cont.isEmpty()) {
  397. decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
  398. } else {
  399. AlgorithmParameters params = AlgorithmParameters
  400. .getInstance(paramsAlgo);
  401. params.init(Base64.decode(cont));
  402. decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, params);
  403. }
  404. } catch (Exception e) {
  405. throw error(e);
  406. }
  407. }
  408. @Override
  409. InputStream decrypt(InputStream input) throws IOException {
  410. try {
  411. return new CipherInputStream(input, decryptCipher);
  412. } finally {
  413. decryptCipher = null; // Cleanup validate -> decrypt transition.
  414. }
  415. }
  416. }
  417. /**
  418. * Provides JetS3t-like encryption with AES support. Uses V1 connection file
  419. * format. For reference, see: 'jgit-s3-connection-v-1.properties'.
  420. */
  421. static class JGitV1 extends SymmetricEncryption {
  422. static final String VERSION = "1"; //$NON-NLS-1$
  423. // Re-map connection properties V1 -> V2.
  424. static Properties wrap(String algo, String pass) {
  425. Properties props = new Properties();
  426. props.put(AmazonS3.Keys.CRYPTO_ALG, algo);
  427. props.put(AmazonS3.Keys.CRYPTO_VER, VERSION);
  428. props.put(AmazonS3.Keys.PASSWORD, pass);
  429. props.put(algo + Keys.X_ALGO, algo);
  430. props.put(algo + Keys.X_KEY_ALGO, algo);
  431. props.put(algo + Keys.X_KEY_ITER, DEFAULT_KEY_ITER);
  432. props.put(algo + Keys.X_KEY_SIZE, DEFAULT_KEY_SIZE);
  433. props.put(algo + Keys.X_KEY_SALT, DEFAULT_KEY_SALT);
  434. return props;
  435. }
  436. JGitV1(String algo, String pass)
  437. throws GeneralSecurityException {
  438. super(wrap(algo, pass));
  439. String name = cipherAlgo.toUpperCase(Locale.ROOT);
  440. Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
  441. if (!matcherPBE.matches())
  442. throw new GeneralSecurityException(
  443. JGitText.get().encryptionOnlyPBE);
  444. }
  445. }
  446. /**
  447. * Supports both PBE and non-PBE algorithms. Uses V2 connection file format.
  448. * For reference, see: 'jgit-s3-connection-v-2.properties'.
  449. */
  450. static class JGitV2 extends SymmetricEncryption {
  451. static final String VERSION = "2"; //$NON-NLS-1$
  452. JGitV2(Properties props)
  453. throws GeneralSecurityException {
  454. super(props);
  455. }
  456. }
  457. /**
  458. * Encryption factory.
  459. *
  460. * @param props
  461. * @return instance
  462. * @throws GeneralSecurityException
  463. */
  464. static WalkEncryption instance(Properties props)
  465. throws GeneralSecurityException {
  466. String algo = props.getProperty(AmazonS3.Keys.CRYPTO_ALG, Vals.DEFAULT_ALGO);
  467. String vers = props.getProperty(AmazonS3.Keys.CRYPTO_VER, Vals.DEFAULT_VERS);
  468. String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
  469. if (pass == null) // Disable encryption.
  470. return WalkEncryption.NONE;
  471. switch (vers) {
  472. case Vals.DEFAULT_VERS:
  473. return new JetS3tV2(algo, pass);
  474. case JGitV1.VERSION:
  475. return new JGitV1(algo, pass);
  476. case JGitV2.VERSION:
  477. return new JGitV2(props);
  478. default:
  479. throw new GeneralSecurityException(MessageFormat.format(
  480. JGitText.get().unsupportedEncryptionVersion, vers));
  481. }
  482. }
  483. }