cryptography.adoc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. [[crypto]]
  2. = Spring Security Crypto Module
  3. [[spring-security-crypto-introduction]]
  4. The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding.
  5. The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code.
  6. [[spring-security-crypto-encryption]]
  7. == Encryptors
  8. The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors.
  9. This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form.
  10. You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings.
  11. Encryptors are thread-safe.
  12. [NOTE]
  13. ====
  14. Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations.
  15. ====
  16. [[spring-security-crypto-encryption-bytes]]
  17. === BytesEncryptor
  18. You can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`:
  19. .BytesEncryptor
  20. ====
  21. .Java
  22. [source,java,role="primary"]
  23. ----
  24. Encryptors.stronger("password", "salt");
  25. ----
  26. .Kotlin
  27. [source,kotlin,role="secondary"]
  28. ----
  29. Encryptors.stronger("password", "salt")
  30. ----
  31. ====
  32. The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with
  33. Galois Counter Mode (GCM).
  34. It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
  35. This method requires Java 6.
  36. The password used to generate the `SecretKey` should be kept in a secure place and should not be shared.
  37. The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised.
  38. A 16-byte random initialization vector is also applied so that each encrypted message is unique.
  39. The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length.
  40. You can generate such a salt by using a `KeyGenerator`:
  41. .Generating a key
  42. ====
  43. .Java
  44. [source,java,role="primary"]
  45. ----
  46. String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
  47. ----
  48. .Kotlin
  49. [source,kotlin,role="secondary"]
  50. ----
  51. val salt = KeyGenerators.string().generateKey() // generates a random 8-byte salt that is then hex-encoded
  52. ----
  53. ====
  54. You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode.
  55. This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any
  56. guarantees about the authenticity of the data.
  57. For a more secure alternative, use `Encryptors.stronger`.
  58. [[spring-security-crypto-encryption-text]]
  59. === TextEncryptor
  60. You can use the `Encryptors.text` factory method to construct a standard TextEncryptor:
  61. .TextEncryptor
  62. ====
  63. .Java
  64. [source,java,role="primary"]
  65. ----
  66. Encryptors.text("password", "salt");
  67. ----
  68. .Kotlin
  69. [source,kotlin,role="secondary"]
  70. ----
  71. Encryptors.text("password", "salt")
  72. ----
  73. ====
  74. A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data.
  75. Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database.
  76. You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`:
  77. .Queryable TextEncryptor
  78. ====
  79. .Java
  80. [source,java,role="primary"]
  81. ----
  82. Encryptors.queryableText("password", "salt");
  83. ----
  84. .Kotlin
  85. [source,kotlin,role="secondary"]
  86. ----
  87. Encryptors.queryableText("password", "salt")
  88. ----
  89. ====
  90. The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling.
  91. The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated.
  92. This means the same text encrypted multiple times always produces the same encryption result.
  93. This is less secure but necessary for encrypted data that needs to be queried against.
  94. An example of queryable encrypted text would be an OAuth `apiKey`.
  95. [[spring-security-crypto-keygenerators]]
  96. == Key Generators
  97. The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators.
  98. By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys.
  99. You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys.
  100. `KeyGenerators` is a thread-safe class.
  101. === BytesKeyGenerator
  102. You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance:
  103. .BytesKeyGenerator
  104. ====
  105. .Java
  106. [source,java,role="primary"]
  107. ----
  108. BytesKeyGenerator generator = KeyGenerators.secureRandom();
  109. byte[] key = generator.generateKey();
  110. ----
  111. .Kotlin
  112. [source,kotlin,role="secondary"]
  113. ----
  114. val generator = KeyGenerators.secureRandom()
  115. val key = generator.generateKey()
  116. ----
  117. ====
  118. The default key length is 8 bytes.
  119. A `KeyGenerators.secureRandom` variant provides control over the key length:
  120. .KeyGenerators.secureRandom
  121. ====
  122. .Java
  123. [source,java,role="primary"]
  124. ----
  125. KeyGenerators.secureRandom(16);
  126. ----
  127. .Kotlin
  128. [source,kotlin,role="secondary"]
  129. ----
  130. KeyGenerators.secureRandom(16)
  131. ----
  132. ====
  133. Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation:
  134. .KeyGenerators.shared
  135. ====
  136. .Java
  137. [source,java,role="primary"]
  138. ----
  139. KeyGenerators.shared(16);
  140. ----
  141. .Kotlin
  142. [source,kotlin,role="secondary"]
  143. ----
  144. KeyGenerators.shared(16)
  145. ----
  146. ====
  147. === StringKeyGenerator
  148. You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`:
  149. .StringKeyGenerator
  150. ====
  151. .Java
  152. [source,java,role="primary"]
  153. ----
  154. KeyGenerators.string();
  155. ----
  156. .Kotlin
  157. [source,kotlin,role="secondary"]
  158. ----
  159. KeyGenerators.string()
  160. ----
  161. ====
  162. [[spring-security-crypto-passwordencoders]]
  163. == Password Encoding
  164. The password package of the `spring-security-crypto` module provides support for encoding passwords.
  165. `PasswordEncoder` is the central service interface and has the following signature:
  166. ====
  167. [source,java]
  168. ----
  169. public interface PasswordEncoder {
  170. String encode(CharSequence rawPassword);
  171. boolean matches(CharSequence rawPassword, String encodedPassword);
  172. default boolean upgradeEncoding(String encodedPassword) {
  173. return false;
  174. }
  175. }
  176. ----
  177. ====
  178. The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`.
  179. This method is designed to support password-based authentication schemes.
  180. The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords.
  181. Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers.
  182. You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31.
  183. The higher the value, the more work has to be done to calculate the hash.
  184. The default value is `10`.
  185. You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash.
  186. The following example uses the `BCryptPasswordEncoder`:
  187. .BCryptPasswordEncoder
  188. ====
  189. .Java
  190. [source,java,role="primary"]
  191. ----
  192. // Create an encoder with strength 16
  193. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
  194. String result = encoder.encode("myPassword");
  195. assertTrue(encoder.matches("myPassword", result));
  196. ----
  197. .Kotlin
  198. [source,kotlin,role="secondary"]
  199. ----
  200. // Create an encoder with strength 16
  201. val encoder = BCryptPasswordEncoder(16)
  202. val result: String = encoder.encode("myPassword")
  203. assertTrue(encoder.matches("myPassword", result))
  204. ----
  205. ====
  206. The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords.
  207. To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system.
  208. The following system uses the `Pbkdf2PasswordEncoder`:
  209. .Pbkdf2PasswordEncoder
  210. ====
  211. .Java
  212. [source,java,role="primary"]
  213. ----
  214. // Create an encoder with all the defaults
  215. Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
  216. String result = encoder.encode("myPassword");
  217. assertTrue(encoder.matches("myPassword", result));
  218. ----
  219. .Kotlin
  220. [source,kotlin,role="secondary"]
  221. ----
  222. // Create an encoder with all the defaults
  223. val encoder = Pbkdf2PasswordEncoder()
  224. val result: String = encoder.encode("myPassword")
  225. assertTrue(encoder.matches("myPassword", result))
  226. ----
  227. ====