Commits

Anonymous committed 74cfdc5 Draft

added toyHkdf

also made bouncyHkdf result unsigned

Comments (0)

Files changed (7)

crypto/bouncycastle/digest.ceylon

 import crypto.spec { Digest, Whirlpool, Sha1 }
 import crypto.spec.util { signedToUnsignedBytes }
 
+shared alias SupportedDigests => Whirlpool|Sha1;
+
+ExtendedDigest javaDigest(SupportedDigests algorithm) {
+    switch (algorithm)
+    case (is Whirlpool) {
+        return WhirlpoolDigest();
+    }
+    case (is Sha1) {
+        return SHA1Digest();
+    }
+}
+
+// TODO: compiler bug: can't use SupportedDigests here for some reason
 shared object bouncyDigest
         satisfies Digest<Whirlpool|Sha1> {
-    shared actual [Integer+] digest(Whirlpool|Sha1 algorithm, [Integer+] bytes) {
-        ExtendedDigest digest;
-        switch (algorithm)
-        case (is Whirlpool) {
-            digest = WhirlpoolDigest();
-        }
-        case (is Sha1) {
-            digest = SHA1Digest();
-        }
-        
+    shared actual [Integer+] digest(Whirlpool|Sha1 algorithm,
+            [Integer+] bytes) {
+        value digest = javaDigest(algorithm);
+
         digest.update(arrays.toByteArray(bytes), 0, bytes.size);
         value buf = newByteBuffer(digest.digestSize);
         digest.doFinal(arrays.asByteArray(buf.bytes()), 0);

crypto/bouncycastle/hmac.ceylon

 import java.lang { arrays }
 
 import org.bouncycastle.crypto.macs { HMac }
-import org.bouncycastle.crypto.digests { WhirlpoolDigest, SHA1Digest }
 import org.bouncycastle.crypto.params { KeyParameter }
 
-import crypto.spec { Hmac, Whirlpool, Sha1 }
+import crypto.spec { Hmac, Sha1, Whirlpool }
 import ceylon.io.buffer { newByteBuffer }
 import crypto.spec.util { signedToUnsignedBytes }
 
+// TODO: compiler bug: can't use SupportedDigests here for some reason
 shared object bouncyHmac
-        satisfies Hmac<Sha1|Whirlpool> {
-    shared actual [Integer+] hmac(Sha1|Whirlpool algorithm, [Integer+] key,
+        satisfies Hmac<Whirlpool|Sha1> {
+    shared actual [Integer+] hmac(Whirlpool|Sha1 algorithm, [Integer+] key,
             [Integer+] bytes) {
-        HMac hmac;
-        switch (algorithm)
-        case (is Whirlpool) {
-            hmac = HMac(WhirlpoolDigest());
-        }
-        case (is Sha1) {
-            hmac = HMac(SHA1Digest());
-        }
+        HMac hmac = HMac(javaDigest(algorithm));
         
         hmac.init(KeyParameter(arrays.toByteArray(key)));
         hmac.update(arrays.toByteArray(bytes), 0, bytes.size);

crypto/bouncycastle/keygen.ceylon

 import java.lang { arrays }
 
 import org.bouncycastle.crypto.generators { HKDFBytesGenerator }
-import org.bouncycastle.crypto.digests { WhirlpoolDigest }
 import org.bouncycastle.crypto.params { HKDFParameters }
 
-import crypto.spec { Whirlpool, HKDF }
+import crypto.spec { HKDF, Sha1, Whirlpool }
+import crypto.spec.util { signedToUnsignedBytes }
 
+// TODO: compiler bug: can't use SupportedDigests here for some reason
 shared object bouncyHkdf
-        satisfies HKDF<Whirlpool> {
-    shared actual [Integer+] generate(Whirlpool algorithm,
+        satisfies HKDF<Whirlpool|Sha1> {
+    shared actual [Integer+] generate(Whirlpool|Sha1 algorithm,
             [Integer+] secret, [Integer+] nonce, [Integer+] info, Integer size) {
         assert(size > 0);
         value buf = newByteBuffer(size);
-        value hkdf = HKDFBytesGenerator(WhirlpoolDigest());
+        value hkdf = HKDFBytesGenerator(javaDigest(algorithm));
         hkdf.init(HKDFParameters(
             arrays.toByteArray(secret),
             arrays.toByteArray(nonce),
         hkdf.generateBytes(arrays.asByteArray(buf.bytes()), 0, size);
         buf.flip();
         assert(nonempty bytes = buf.bytes().sequence);
-        return bytes;
+        return signedToUnsignedBytes(bytes);
     }
 }

crypto/spec/keygen.ceylon

+"HMAC-based Extract-and-Expand Key Derivation Function as defined in RFC5869."
 shared interface HKDF<SupportedAlgorithms>
         given SupportedAlgorithms satisfies DigestAlgorithm {
     shared formal [Integer+] generate(SupportedAlgorithms algorithm,

crypto/test/keygen.ceylon

+import crypto.spec { sha1 }
+import crypto.spec.util { codepointsOf }
+import crypto.bouncycastle { bouncyHkdf }
+import crypto.toy { toyHkdf }
+
+void keygen() {
+    assert(nonempty secret = codepointsOf("Hello world!").sequence);
+    assert(nonempty nonce = codepointsOf("asdf").sequence);
+    assert(nonempty info = codepointsOf("Keygen test").sequence);
+    
+    value keyBytesSize = 256 / 8;
+    value bouncyKeyBytes = bouncyHkdf.generate(sha1, secret, nonce, info,
+        keyBytesSize);
+    value toyKeyBytes = toyHkdf.generate(sha1, secret, nonce, info, keyBytesSize);
+    
+    assert(bouncyKeyBytes == toyKeyBytes);
+}

crypto/test/run.ceylon

     bouncy();
     digest();
     hmac();
+    keygen();
 }

crypto/toy/keygen.ceylon

+import crypto.spec { HKDF }
+import ceylon.math.float { ceiling }
+
+shared object toyHkdf
+        satisfies HKDF<SupportedDigests> {   
+    shared actual [Integer+] generate(SupportedDigests algorithm,
+            [Integer+] secret, [Integer+] nonce, [Integer+] info, Integer size) {
+        assert(0 < size <= 255 * algorithm.size);
+        
+        // Extract
+        value pseudorandomKey = toyHmac.hmac(algorithm, nonce, secret);
+        
+        // Expand
+        value n = ceiling(size.float / algorithm.size).integer;
+        assert(nonempty result =
+            (1..n).fold([], ([Integer*] partial, Integer c) =>
+                partial.chain(toyHmac.hmac(algorithm, pseudorandomKey,
+                    partial.terminal(algorithm.size).chain(info)
+                    .sequence.withTrailing(c)))
+                .sequence)
+            .taking(size).sequence);
+        return result;
+    }
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.