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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. protected void validateImpl(final HttpURLConnection u, final String prefix,
  86. final String version, final String name) throws IOException {
  87. String v;
  88. v = u.getHeaderField(prefix + JETS3T_CRYPTO_VER);
  89. if (v == null)
  90. v = ""; //$NON-NLS-1$
  91. if (!version.equals(v))
  92. throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionVersion, v));
  93. v = u.getHeaderField(prefix + JETS3T_CRYPTO_ALG);
  94. if (v == null)
  95. v = ""; //$NON-NLS-1$
  96. // Standard names are not case-sensitive.
  97. // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
  98. if (!name.equalsIgnoreCase(v))
  99. throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionAlgorithm, v));
  100. }
  101. IOException error(final Throwable why) {
  102. return new IOException(MessageFormat
  103. .format(JGitText.get().encryptionError,
  104. why.getMessage()), why);
  105. }
  106. private static class NoEncryption extends WalkEncryption {
  107. @Override
  108. void request(HttpURLConnection u, String prefix) {
  109. // Don't store any request properties.
  110. }
  111. @Override
  112. void validate(final HttpURLConnection u, final String prefix)
  113. throws IOException {
  114. validateImpl(u, prefix, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
  115. }
  116. @Override
  117. InputStream decrypt(InputStream in) {
  118. return in;
  119. }
  120. @Override
  121. OutputStream encrypt(OutputStream os) {
  122. return os;
  123. }
  124. }
  125. /**
  126. * JetS3t compatibility reference: <a href=
  127. * "https://bitbucket.org/jmurty/jets3t/src/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java">
  128. * EncryptionUtil.java</a>
  129. * <p>
  130. * Note: EncryptionUtil is inadequate:
  131. * <li>EncryptionUtil.isCipherAvailableForUse checks encryption only which
  132. * "always works", but in JetS3t both encryption and decryption use non-IV
  133. * aware algorithm parameters for all PBE specs, which breaks in case of AES
  134. * <li>that means that only non-IV algorithms will work round trip in
  135. * JetS3t, such as PBEWithMD5AndDES and PBEWithSHAAndTwofish-CBC
  136. * <li>any AES based algorithms such as "PBE...With...And...AES" will not
  137. * work, since they need proper IV setup
  138. */
  139. static class JetS3tV2 extends WalkEncryption {
  140. static final String VERSION = "2"; //$NON-NLS-1$
  141. static final String ALGORITHM = "PBEWithMD5AndDES"; //$NON-NLS-1$
  142. static final int ITERATIONS = 5000;
  143. static final int KEY_SIZE = 32;
  144. static final byte[] SALT = { //
  145. (byte) 0xA4, (byte) 0x0B, (byte) 0xC8, (byte) 0x34, //
  146. (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 //
  147. };
  148. // Size 16, see com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE
  149. static final byte[] ZERO_AES_IV = new byte[16];
  150. private static final String CRYPTO_VER = VERSION;
  151. private final String cryptoAlg;
  152. private final SecretKey secretKey;
  153. private final AlgorithmParameterSpec paramSpec;
  154. JetS3tV2(final String algo, final String key)
  155. throws GeneralSecurityException {
  156. cryptoAlg = algo;
  157. // Verify if cipher is present.
  158. Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  159. // Standard names are not case-sensitive.
  160. // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
  161. String cryptoName = cryptoAlg.toUpperCase(Locale.ROOT);
  162. if (!cryptoName.startsWith("PBE")) //$NON-NLS-1$
  163. throw new GeneralSecurityException(JGitText.get().encryptionOnlyPBE);
  164. PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
  165. secretKey = SecretKeyFactory.getInstance(algo).generateSecret(keySpec);
  166. // Detect algorithms which require initialization vector.
  167. boolean useIV = cryptoName.contains("AES"); //$NON-NLS-1$
  168. // PBEParameterSpec algorithm parameters are supported from Java 8.
  169. if (useIV) {
  170. // Support IV where possible:
  171. // * since JCE provider uses random IV for PBE/AES
  172. // * and there is no place to store dynamic IV in JetS3t V2
  173. // * we use static IV, and tolerate increased security risk
  174. // TODO back port this change to JetS3t V2
  175. // See:
  176. // https://bitbucket.org/jmurty/jets3t/raw/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java
  177. // http://cr.openjdk.java.net/~mullan/webrevs/ascarpin/webrev.00/raw_files/new/src/share/classes/com/sun/crypto/provider/PBES2Core.java
  178. IvParameterSpec paramIV = new IvParameterSpec(ZERO_AES_IV);
  179. paramSpec = new PBEParameterSpec(SALT, ITERATIONS, paramIV);
  180. } else {
  181. // Strict legacy JetS3t V2 compatibility, with no IV support.
  182. paramSpec = new PBEParameterSpec(SALT, ITERATIONS);
  183. }
  184. // Verify if cipher + key are allowed by policy.
  185. cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
  186. cipher.doFinal();
  187. }
  188. @Override
  189. void request(final HttpURLConnection u, final String prefix) {
  190. u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, CRYPTO_VER);
  191. u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, cryptoAlg);
  192. }
  193. @Override
  194. void validate(final HttpURLConnection u, final String prefix)
  195. throws IOException {
  196. validateImpl(u, prefix, CRYPTO_VER, cryptoAlg);
  197. }
  198. @Override
  199. OutputStream encrypt(final OutputStream os) throws IOException {
  200. try {
  201. final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  202. cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
  203. return new CipherOutputStream(os, cipher);
  204. } catch (GeneralSecurityException e) {
  205. throw error(e);
  206. }
  207. }
  208. @Override
  209. InputStream decrypt(final InputStream in) throws IOException {
  210. try {
  211. final Cipher cipher = InsecureCipherFactory.create(cryptoAlg);
  212. cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
  213. return new CipherInputStream(in, cipher);
  214. } catch (GeneralSecurityException e) {
  215. throw error(e);
  216. }
  217. }
  218. }
  219. /** Encryption property names. */
  220. interface Keys {
  221. // Remote S3 meta: V1 algorithm name or V2 profile name.
  222. String JGIT_PROFILE = "jgit-crypto-profile"; //$NON-NLS-1$
  223. // Remote S3 meta: JGit encryption implementation version.
  224. String JGIT_VERSION = "jgit-crypto-version"; //$NON-NLS-1$
  225. // Remote S3 meta: base-64 encoded cipher algorithm parameters.
  226. String JGIT_CONTEXT = "jgit-crypto-context"; //$NON-NLS-1$
  227. // Amazon S3 connection configuration file profile property suffixes:
  228. String X_ALGO = ".algo"; //$NON-NLS-1$
  229. String X_KEY_ALGO = ".key.algo"; //$NON-NLS-1$
  230. String X_KEY_SIZE = ".key.size"; //$NON-NLS-1$
  231. String X_KEY_ITER = ".key.iter"; //$NON-NLS-1$
  232. String X_KEY_SALT = ".key.salt"; //$NON-NLS-1$
  233. }
  234. /** Encryption constants and defaults. */
  235. interface Vals {
  236. // Compatibility defaults.
  237. String DEFAULT_VERS = "0"; //$NON-NLS-1$
  238. String DEFAULT_ALGO = JetS3tV2.ALGORITHM;
  239. String DEFAULT_KEY_ALGO = JetS3tV2.ALGORITHM;
  240. String DEFAULT_KEY_SIZE = Integer.toString(JetS3tV2.KEY_SIZE);
  241. String DEFAULT_KEY_ITER = Integer.toString(JetS3tV2.ITERATIONS);
  242. String DEFAULT_KEY_SALT = DatatypeConverter.printHexBinary(JetS3tV2.SALT);
  243. String EMPTY = ""; //$NON-NLS-1$
  244. // Match white space.
  245. String REGEX_WS = "\\s+"; //$NON-NLS-1$
  246. // Match PBE ciphers, i.e: PBEWithMD5AndDES
  247. String REGEX_PBE = "(PBE).*(WITH).+(AND).+"; //$NON-NLS-1$
  248. // Match transformation ciphers, i.e: AES/CBC/PKCS5Padding
  249. String REGEX_TRANS = "(.+)/(.+)/(.+)"; //$NON-NLS-1$
  250. }
  251. static GeneralSecurityException securityError(String message) {
  252. return new GeneralSecurityException(
  253. MessageFormat.format(JGitText.get().encryptionError, message));
  254. }
  255. /**
  256. * Base implementation of JGit symmetric encryption. Supports V2 properties
  257. * format.
  258. */
  259. static abstract class SymmetricEncryption extends WalkEncryption
  260. implements Keys, Vals {
  261. /** Encryption profile, root name of group of related properties. */
  262. final String profile;
  263. /** Encryption version, reflects actual implementation class. */
  264. final String version;
  265. /** Full cipher algorithm name. */
  266. final String cipherAlgo;
  267. /** Cipher algorithm name for parameters lookup. */
  268. final String paramsAlgo;
  269. /** Generated secret key. */
  270. final SecretKey secretKey;
  271. SymmetricEncryption(Properties props) throws GeneralSecurityException {
  272. profile = props.getProperty(AmazonS3.Keys.CRYPTO_ALG);
  273. version = props.getProperty(AmazonS3.Keys.CRYPTO_VER);
  274. String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
  275. cipherAlgo = props.getProperty(profile + X_ALGO, DEFAULT_ALGO);
  276. String keyAlgo = props.getProperty(profile + X_KEY_ALGO, DEFAULT_KEY_ALGO);
  277. String keySize = props.getProperty(profile + X_KEY_SIZE, DEFAULT_KEY_SIZE);
  278. String keyIter = props.getProperty(profile + X_KEY_ITER, DEFAULT_KEY_ITER);
  279. String keySalt = props.getProperty(profile + X_KEY_SALT, DEFAULT_KEY_SALT);
  280. // Verify if cipher is present.
  281. Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
  282. // Verify if key factory is present.
  283. SecretKeyFactory factory = SecretKeyFactory.getInstance(keyAlgo);
  284. final int size;
  285. try {
  286. size = Integer.parseInt(keySize);
  287. } catch (Exception e) {
  288. throw securityError(X_KEY_SIZE + EMPTY + keySize);
  289. }
  290. final int iter;
  291. try {
  292. iter = Integer.parseInt(keyIter);
  293. } catch (Exception e) {
  294. throw securityError(X_KEY_ITER + EMPTY + keyIter);
  295. }
  296. final byte[] salt;
  297. try {
  298. salt = DatatypeConverter
  299. .parseHexBinary(keySalt.replaceAll(REGEX_WS, EMPTY));
  300. } catch (Exception e) {
  301. throw securityError(X_KEY_SALT + EMPTY + keySalt);
  302. }
  303. KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iter, size);
  304. SecretKey keyBase = factory.generateSecret(keySpec);
  305. String name = cipherAlgo.toUpperCase(Locale.ROOT);
  306. Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
  307. Matcher matcherTrans = Pattern.compile(REGEX_TRANS).matcher(name);
  308. if (matcherPBE.matches()) {
  309. paramsAlgo = cipherAlgo;
  310. secretKey = keyBase;
  311. } else if (matcherTrans.find()) {
  312. paramsAlgo = matcherTrans.group(1);
  313. secretKey = new SecretKeySpec(keyBase.getEncoded(), paramsAlgo);
  314. } else {
  315. throw new GeneralSecurityException(MessageFormat.format(
  316. JGitText.get().unsupportedEncryptionAlgorithm,
  317. cipherAlgo));
  318. }
  319. // Verify if cipher + key are allowed by policy.
  320. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  321. cipher.doFinal();
  322. }
  323. // Shared state encrypt -> request.
  324. volatile String context;
  325. @Override
  326. OutputStream encrypt(OutputStream output) throws IOException {
  327. try {
  328. Cipher cipher = InsecureCipherFactory.create(cipherAlgo);
  329. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  330. AlgorithmParameters params = cipher.getParameters();
  331. if (params == null) {
  332. context = EMPTY;
  333. } else {
  334. context = Base64.encodeBytes(params.getEncoded());
  335. }
  336. return new CipherOutputStream(output, cipher);
  337. } catch (Exception e) {
  338. throw error(e);
  339. }
  340. }
  341. @Override
  342. void request(HttpURLConnection conn, String prefix) throws IOException {
  343. conn.setRequestProperty(prefix + JGIT_PROFILE, profile);
  344. conn.setRequestProperty(prefix + JGIT_VERSION, version);
  345. conn.setRequestProperty(prefix + JGIT_CONTEXT, context);
  346. // No cleanup:
  347. // single encrypt can be followed by several request
  348. // from the AmazonS3.putImpl() multiple retry attempts
  349. // context = null; // Cleanup encrypt -> request transition.
  350. // TODO re-factor AmazonS3.putImpl to be more transaction-like
  351. }
  352. // Shared state validate -> decrypt.
  353. volatile Cipher decryptCipher;
  354. @Override
  355. void validate(HttpURLConnection conn, String prefix)
  356. throws IOException {
  357. String prof = conn.getHeaderField(prefix + JGIT_PROFILE);
  358. String vers = conn.getHeaderField(prefix + JGIT_VERSION);
  359. String cont = conn.getHeaderField(prefix + JGIT_CONTEXT);
  360. if (prof == null) {
  361. throw new IOException(MessageFormat
  362. .format(JGitText.get().encryptionError, JGIT_PROFILE));
  363. }
  364. if (vers == null) {
  365. throw new IOException(MessageFormat
  366. .format(JGitText.get().encryptionError, JGIT_VERSION));
  367. }
  368. if (cont == null) {
  369. throw new IOException(MessageFormat
  370. .format(JGitText.get().encryptionError, JGIT_CONTEXT));
  371. }
  372. if (!profile.equals(prof)) {
  373. throw new IOException(MessageFormat.format(
  374. JGitText.get().unsupportedEncryptionAlgorithm, prof));
  375. }
  376. if (!version.equals(vers)) {
  377. throw new IOException(MessageFormat.format(
  378. JGitText.get().unsupportedEncryptionVersion, vers));
  379. }
  380. try {
  381. decryptCipher = InsecureCipherFactory.create(cipherAlgo);
  382. if (cont.isEmpty()) {
  383. decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
  384. } else {
  385. AlgorithmParameters params = AlgorithmParameters
  386. .getInstance(paramsAlgo);
  387. params.init(Base64.decode(cont));
  388. decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, params);
  389. }
  390. } catch (Exception e) {
  391. throw error(e);
  392. }
  393. }
  394. @Override
  395. InputStream decrypt(InputStream input) throws IOException {
  396. try {
  397. return new CipherInputStream(input, decryptCipher);
  398. } finally {
  399. decryptCipher = null; // Cleanup validate -> decrypt transition.
  400. }
  401. }
  402. }
  403. /**
  404. * Provides JetS3t-like encryption with AES support. Uses V1 connection file
  405. * format. For reference, see: 'jgit-s3-connection-v-1.properties'.
  406. */
  407. static class JGitV1 extends SymmetricEncryption {
  408. static final String VERSION = "1"; //$NON-NLS-1$
  409. // Re-map connection properties V1 -> V2.
  410. static Properties wrap(String algo, String pass) {
  411. Properties props = new Properties();
  412. props.put(AmazonS3.Keys.CRYPTO_ALG, algo);
  413. props.put(AmazonS3.Keys.CRYPTO_VER, VERSION);
  414. props.put(AmazonS3.Keys.PASSWORD, pass);
  415. props.put(algo + Keys.X_ALGO, algo);
  416. props.put(algo + Keys.X_KEY_ALGO, algo);
  417. props.put(algo + Keys.X_KEY_ITER, DEFAULT_KEY_ITER);
  418. props.put(algo + Keys.X_KEY_SIZE, DEFAULT_KEY_SIZE);
  419. props.put(algo + Keys.X_KEY_SALT, DEFAULT_KEY_SALT);
  420. return props;
  421. }
  422. JGitV1(String algo, String pass)
  423. throws GeneralSecurityException {
  424. super(wrap(algo, pass));
  425. String name = cipherAlgo.toUpperCase(Locale.ROOT);
  426. Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
  427. if (!matcherPBE.matches())
  428. throw new GeneralSecurityException(
  429. JGitText.get().encryptionOnlyPBE);
  430. }
  431. }
  432. /**
  433. * Supports both PBE and non-PBE algorithms. Uses V2 connection file format.
  434. * For reference, see: 'jgit-s3-connection-v-2.properties'.
  435. */
  436. static class JGitV2 extends SymmetricEncryption {
  437. static final String VERSION = "2"; //$NON-NLS-1$
  438. JGitV2(Properties props)
  439. throws GeneralSecurityException {
  440. super(props);
  441. }
  442. }
  443. /**
  444. * Encryption factory.
  445. *
  446. * @param props
  447. * @return instance
  448. * @throws GeneralSecurityException
  449. */
  450. static WalkEncryption instance(Properties props)
  451. throws GeneralSecurityException {
  452. String algo = props.getProperty(AmazonS3.Keys.CRYPTO_ALG, Vals.DEFAULT_ALGO);
  453. String vers = props.getProperty(AmazonS3.Keys.CRYPTO_VER, Vals.DEFAULT_VERS);
  454. String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
  455. if (pass == null) // Disable encryption.
  456. return WalkEncryption.NONE;
  457. switch (vers) {
  458. case Vals.DEFAULT_VERS:
  459. return new JetS3tV2(algo, pass);
  460. case JGitV1.VERSION:
  461. return new JGitV1(algo, pass);
  462. case JGitV2.VERSION:
  463. return new JGitV2(props);
  464. default:
  465. throw new GeneralSecurityException(MessageFormat.format(
  466. JGitText.get().unsupportedEncryptionVersion, vers));
  467. }
  468. }
  469. }