Permalink
Browse files

inital commit

  • Loading branch information...
Philipp Brüll
Philipp Brüll committed Jan 17, 2013
0 parents commit fc885a29c8627fac16ea968b728cdaefa431919b
Showing with 5,848 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +23 −0 README.md
  3. +37 −0 build.gradle
  4. +16 −0 epd-kotlin.iml
  5. BIN lib/hamcrest-core-1.1-sources.jar
  6. BIN lib/hamcrest-core-1.1.jar
  7. BIN lib/json-simple-1.1.1-javadoc.jar
  8. BIN lib/json-simple-1.1.1-sources.jar
  9. BIN lib/json-simple-1.1.1.jar
  10. BIN lib/junit-4.10-javadoc.jar
  11. BIN lib/junit-4.10-sources.jar
  12. BIN lib/junit-4.10.jar
  13. BIN lib/junit-4.9.jar
  14. BIN lib/kotlin-runtime.jar
  15. +31 −0 src/main/kotlin/com/anyaku/Debug.kt
  16. +9 −0 src/main/kotlin/com/anyaku/crypt/Password.kt
  17. +6 −0 src/main/kotlin/com/anyaku/crypt/PasswordSalt.kt
  18. +25 −0 src/main/kotlin/com/anyaku/crypt/asymmetric/RSAKey.kt
  19. +33 −0 src/main/kotlin/com/anyaku/crypt/asymmetric/RSAKeyPair.kt
  20. +15 −0 src/main/kotlin/com/anyaku/crypt/asymmetric/RSASignature.kt
  21. +26 −0 src/main/kotlin/com/anyaku/crypt/asymmetric/Signer.kt
  22. +91 −0 src/main/kotlin/com/anyaku/crypt/coder/coder.kt
  23. +14 −0 src/main/kotlin/com/anyaku/crypt/crypt.kt
  24. +8 −0 src/main/kotlin/com/anyaku/crypt/symmetric/AESKey.kt
  25. +26 −0 src/main/kotlin/com/anyaku/epd/Signer.kt
  26. +18 −0 src/main/kotlin/com/anyaku/epd/epd.kt
  27. +17 −0 src/main/kotlin/com/anyaku/epd/structure/Document.kt
  28. +10 −0 src/main/kotlin/com/anyaku/epd/structure/Section.kt
  29. +11 −0 src/main/kotlin/com/anyaku/epd/structure/obj/Mapable.kt
  30. +68 −0 src/main/kotlin/com/anyaku/epd/structure/obj/MutableObjectEntrySet.kt
  31. +17 −0 src/main/kotlin/com/anyaku/epd/structure/obj/MutableObjectIterator.kt
  32. +49 −0 src/main/kotlin/com/anyaku/epd/structure/obj/MutableObjectMap.kt
  33. +20 −0 src/main/kotlin/com/anyaku/epd/structure/obj/MutableObjectMapEntry.kt
  34. +30 −0 src/main/kotlin/com/anyaku/epd/structure/v1/Document.kt
  35. +17 −0 src/main/kotlin/com/anyaku/epd/structure/v1/Section.kt
  36. +26 −0 src/main/kotlin/com/anyaku/json/json.kt
  37. +38 −0 src/main/kotlin/com/anyaku/map/map.kt
  38. +34 −0 src/test/kotlin/com/anyaku/test/Tools.kt
  39. +19 −0 src/test/kotlin/com/anyaku/test/crypt/asymmetric/RSAKeyPairTest.kt
  40. +31 −0 src/test/kotlin/com/anyaku/test/crypt/asymmetric/SignerTest.kt
  41. +35 −0 src/test/kotlin/com/anyaku/test/crypt/coder/coderTest.kt
  42. +19 −0 src/test/kotlin/com/anyaku/test/crypt/cryptTest.kt
  43. +40 −0 src/test/kotlin/com/anyaku/test/epd/SignerTest.kt
  44. +22 −0 src/test/kotlin/com/anyaku/test/epd/epdTest.kt
  45. +20 −0 src/test/kotlin/com/anyaku/test/fixtures/Profiles.kt
  46. +32 −0 src/test/kotlin/com/anyaku/test/integration/BigIntegerTest.kt
  47. +60 −0 src/test/kotlin/com/anyaku/test/integration/CodingTest.kt
  48. +27 −0 src/test/kotlin/com/anyaku/test/integration/MapStringificationTest.kt
  49. +34 −0 src/test/kotlin/com/anyaku/test/integration/PasswordHashTest.kt
  50. +37 −0 src/test/kotlin/com/anyaku/test/integration/RSAKeyPairTest.kt
  51. +33 −0 src/test/kotlin/com/anyaku/test/integration/RSASignatureTest.kt
  52. +32 −0 src/test/kotlin/com/anyaku/test/integration/javascript/javascript.kt
  53. +17 −0 src/test/kotlin/com/anyaku/test/json/jsonTest.kt
  54. +28 −0 src/test/kotlin/com/anyaku/test/map/mapTest.kt
  55. +27 −0 src/test/kotlin/com/anyaku/test/performance/PasswordHashTest.kt
  56. +22 −0 src/test/kotlin/com/anyaku/test/performance/benchmark/benchmark.kt
  57. +3,892 −0 src/test/resources/epd.js
  58. +702 −0 src/test/resources/profiles.json
@@ -0,0 +1,4 @@
+.idea
+.gradle
+build
+out
@@ -0,0 +1,23 @@
+
+# Encrypted Profile Documents
+
+The encrypted profile document (EPD) format acts as an encryption container of information that the author wants to
+keep private or share with a defined set of other EPD authors. It enables the author to clearly separate private and
+shared data and keep control about what information can be accessed by others. This is achieved by a combination of
+symmetric and asymmetric encryption methods, which are chained together in the process of encrypting and decrypting
+(locking and unlocking) an EPD. Each EPD contains, beside the payload data and some encryption overhead, also
+information about the author and his signature, which enables a random reader to verify the authenticity of the EPD,
+even if the content cannot be unlocked.
+
+This library can handle EPDs and is implemented in pure Javascript. It's compatible with the latest versions of Firefox
+and Chrome.
+
+## Contribution
+
+Any contribution is very welcome. If code is contributed, please make sure that tests are included.
+
+## License
+
+[![Creative Commons License](http://i.creativecommons.org/l/by-nc-sa/3.0/80x15.png)](http://creativecommons.org/licenses/by-nc-sa/3.0/)
+This work is licensed under a
+[Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/).
@@ -0,0 +1,37 @@
+
+buildscript {
+ repositories { mavenRepo url: 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' }
+ dependencies { classpath 'com.github.goldin.plugins.gradle:kotlin:0.2-SNAPSHOT' }
+}
+
+logging.captureStandardOutput LogLevel.INFO
+
+apply plugin: 'java'
+apply plugin: 'kotlin'
+
+final version = '1.0'
+
+jar {
+ manifest {
+ attributes 'Implementation-Title': 'Encrypted Profile Document library',
+ 'Implementation-Version': version
+ }
+}
+
+repositories {
+ mavenCentral()
+ mavenRepo url: 'http://repository.jetbrains.com/kotlin/'
+}
+
+dependencies {
+ compile files( "${ System.getProperty( 'java.home' )}/lib/jce.jar" )
+ compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '0.4.297'
+ compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
+
+ runtime group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: '0.4.297'
+
+ testCompile group: 'junit', name: 'junit', version: '4.+'
+}
+
+test.dependsOn compileKotlin
+test.dependsOn compileTestKotlin
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" name="KotlinRuntime" level="project" />
+ <orderEntry type="library" name="junit-4.9" level="project" />
+ <orderEntry type="library" name="json-simple-1.1.1" level="project" />
+ </component>
+</module>
+
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,31 @@
+package com.anyaku
+
+import java.io.PrintStream
+import java.io.FileOutputStream
+import java.io.FileDescriptor
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+fun debug(message: String) {
+ var output = PrintStream(FileOutputStream(FileDescriptor.out))
+ output.println(message)
+}
+
+fun debug(values: ByteArray) {
+ val message = StringBuilder()
+ for (val value in values) {
+ message.append(value.toString())
+ message.append(", ")
+ }
+ debug(message.toString())
+}
+
+fun debug(values: LongArray) {
+ val message = StringBuilder()
+ for (val value in values) {
+ message.append(value.toString())
+ message.append(", ")
+ }
+ debug(message.toString())
+}
@@ -0,0 +1,9 @@
+package com.anyaku.crypt
+
+import com.anyaku.crypt.symmetric.AESKey
+
+/**
+ * User: phifty
+ */
+
+class Password(val hash: AESKey, val salt: PasswordSalt, val iterations: Int, val keyLength: Int)
@@ -0,0 +1,6 @@
+package com.anyaku.crypt
+
+/**
+ * User: phifty
+ */
+class PasswordSalt(val bytes: ByteArray)
@@ -0,0 +1,25 @@
+package com.anyaku.crypt.asymmetric
+
+import java.math.BigInteger
+import java.security.KeyFactory
+import java.security.spec.RSAPrivateKeySpec
+import java.security.PrivateKey
+import java.security.PublicKey
+import java.security.spec.RSAPublicKeySpec
+
+val keyFactory = KeyFactory.getInstance("RSA") as KeyFactory
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+class RSAKey(val modulus: BigInteger, val exponent: BigInteger) {
+
+ fun toPrivateKey(): PrivateKey {
+ return keyFactory.generatePrivate(RSAPrivateKeySpec(modulus, exponent)) as PrivateKey
+ }
+
+ fun toPublicKey(): PublicKey {
+ return keyFactory.generatePublic(RSAPublicKeySpec(modulus, exponent)) as PublicKey
+ }
+
+}
@@ -0,0 +1,33 @@
+package com.anyaku.crypt.asymmetric
+
+import java.security.KeyPairGenerator
+import java.security.PublicKey
+import java.security.PrivateKey
+import java.security.interfaces.RSAPublicKey
+import java.math.BigInteger
+import java.security.interfaces.RSAPrivateKey
+
+val keyPairGenerator = { (): KeyPairGenerator ->
+ val result = KeyPairGenerator.getInstance("RSA") as KeyPairGenerator
+ result.initialize(1024)
+ result
+}()
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+class RSAKeyPair() {
+ val keyPair = keyPairGenerator.generateKeyPair() as java.security.KeyPair
+
+ public val publicKey: RSAKey
+ get() {
+ val rsaKey = keyPair.getPublic() as RSAPublicKey
+ return RSAKey(rsaKey.getModulus() as BigInteger, rsaKey.getPublicExponent() as BigInteger)
+ }
+ public val privateKey: RSAKey
+ get() {
+ val rsaKey = keyPair.getPrivate() as RSAPrivateKey
+ return RSAKey(rsaKey.getModulus() as BigInteger, rsaKey.getPrivateExponent() as BigInteger)
+ }
+
+}
@@ -0,0 +1,15 @@
+package com.anyaku.crypt.asymmetric
+
+import com.anyaku.crypt.coder
+import com.anyaku.crypt.coder.base64Encode
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+class RSASignature(val bytes: ByteArray) {
+
+ fun toString(): String {
+ return "RSASignature " + base64Encode(bytes)
+ }
+
+}
@@ -0,0 +1,26 @@
+package com.anyaku.crypt.asymmetric
+
+import java.security.Signature
+import com.anyaku.crypt.asymmetric.RSAKey
+import com.anyaku.crypt.coder
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+class Signer(val content: String) {
+
+ private val signature = Signature.getInstance("SHA256withRSA") as Signature
+
+ public fun sign(key: RSAKey): RSASignature {
+ signature.initSign(key.toPrivateKey())
+ signature.update(content.getBytes())
+ return RSASignature(signature.sign() as ByteArray)
+ }
+
+ public fun verify(key: RSAKey, encodedSignature: RSASignature): Boolean {
+ signature.initVerify(key.toPublicKey())
+ signature.update(content.getBytes())
+ return signature.verify(encodedSignature.bytes)
+ }
+
+}
@@ -0,0 +1,91 @@
+package com.anyaku.crypt.coder
+
+import javax.xml.bind.DatatypeConverter
+import java.math.BigInteger
+import com.anyaku.crypt.asymmetric.RSAKey
+import com.anyaku.crypt.asymmetric.RSASignature
+import java.nio.ByteBuffer
+import java.util.Arrays
+import com.anyaku.debug
+import com.anyaku.crypt.symmetric.AESKey
+import javax.crypto.spec.SecretKeySpec
+import com.anyaku.crypt.PasswordSalt
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+fun decode(encoded: String): Any {
+ val code = encoded.substring(0, 1)
+ val data = encoded.substring(1)
+ return when (code) {
+ "A" -> decodeRSAKey(data)
+ "C" -> decodeRSASignature(data)
+ "D" -> decodeAESKey(data)
+ "F" -> decodePasswordSalt(data)
+ else -> throw Exception("unknown type to decode '$code'")
+ }
+}
+
+fun encode(value: Any): String {
+ return when (value) {
+ is RSASignature -> "C" + encodeRSASignature(value)
+ is AESKey -> "D" + encodeAESKey(value)
+ is PasswordSalt -> "F" + encodePasswordSalt(value)
+ else -> throw Exception("unknown type to encode '${value.javaClass}'")
+ }
+}
+
+fun base64Encode(value: ByteArray): String {
+ return DatatypeConverter.printBase64Binary(value) as String
+}
+
+fun base64Decode(encoded: String): ByteArray {
+ return DatatypeConverter.parseBase64Binary(encoded) as ByteArray
+}
+
+private fun decodeRSAKey(encoded: String): RSAKey {
+ val data = base64Decode(encoded)
+ val modulusData = at(data, 0)
+ val modulus = BigInteger(1, modulusData)
+ val exponentData = at(data, 4 + modulusData.size)
+ val exponent = BigInteger(1, exponentData)
+ return RSAKey(modulus, exponent)
+}
+
+private fun decodeRSASignature(encoded: String): RSASignature {
+ return RSASignature(base64Decode(encoded))
+}
+
+private fun decodeAESKey(encoded: String): AESKey {
+ return AESKey(base64Decode(encoded))
+}
+
+private fun decodePasswordSalt(encoded: String): PasswordSalt {
+ return PasswordSalt(base64Decode(encoded))
+}
+
+private fun encodeRSASignature(signature: RSASignature): String {
+ return base64Encode(signature.bytes)
+}
+
+private fun encodeAESKey(key: AESKey): String {
+ return base64Encode(key.bytes)
+}
+
+private fun encodePasswordSalt(salt: PasswordSalt): String {
+ return base64Encode(salt.bytes)
+}
+
+private fun at(data: ByteArray, offset: Int): ByteArray {
+ val length = toInt(range(data, offset, 4)) * 4
+ return range(data, offset + 4, length)
+}
+
+private fun range(value: ByteArray, index: Int, length: Int): ByteArray {
+ return Arrays.copyOfRange(value, index, index + length) as ByteArray
+}
+
+private fun toInt(value: ByteArray): Int {
+ if (value.size != 4) throw RuntimeException("given byte array has the wrong size ${value.size}")
+ return ByteBuffer.wrap(value)?.getInt() as Int
+}
@@ -0,0 +1,14 @@
+package com.anyaku.crypt
+
+import javax.crypto.SecretKeyFactory
+import javax.crypto.SecretKey
+import javax.crypto.spec.PBEKeySpec
+import javax.xml.bind.DatatypeConverter
+import com.anyaku.crypt.symmetric.AESKey
+
+fun password(value: String, salt: PasswordSalt, iterations: Int, keySize: Int): Password {
+ val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") as SecretKeyFactory
+ val spec = PBEKeySpec(value.toCharArray(), salt.bytes, iterations, keySize)
+ val secretKey = secretKeyFactory.generateSecret(spec) as SecretKey
+ return Password(AESKey(secretKey.getEncoded() as ByteArray), salt, iterations, keySize)
+}
@@ -0,0 +1,8 @@
+package com.anyaku.crypt.symmetric
+
+import javax.crypto.SecretKey
+
+/**
+ * User: phifty
+ */
+class AESKey(val bytes: ByteArray)
@@ -0,0 +1,26 @@
+package com.anyaku.epd
+
+import com.anyaku.crypt.coder
+import com.anyaku.crypt.asymmetric.RSAKey
+import java.util.HashMap
+import com.anyaku.epd.structure.Document
+import com.anyaku.map.stringify
+import com.anyaku.debug
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+class Signer(val document: Document) {
+
+ fun verify(): Boolean {
+ val signer = com.anyaku.crypt.asymmetric.Signer(stringify(strippedDocumentMap()))
+ return signer.verify(document.publicKey, document.signature)
+ }
+
+ private fun strippedDocumentMap(): MutableMap<String, Any?> {
+ val result = HashMap(document.map)
+ result.remove("signature")
+ return result
+ }
+
+}
@@ -0,0 +1,18 @@
+package com.anyaku.epd
+
+import com.anyaku.epd.structure.Document
+import com.anyaku.json.parseJson
+
+/**
+ * @author phifty <b.phifty@gmail.com>
+ */
+fun buildDocumentFromJson(json: String): Document {
+ val documentMap = parseJson(json)
+ if (documentMap is MutableMap<*, *>) {
+ val version = documentMap.get("version").toString().toInt()
+ return when (version) {
+ 1 -> com.anyaku.epd.structure.v1.Document(documentMap as MutableMap<String, Any?>)
+ else -> throw Exception("unknown epd version $version")
+ }
+ } else throw Exception("unknown epd structure")
+}
Oops, something went wrong.

0 comments on commit fc885a2

Please sign in to comment.