Compare commits
10
Commits
f412516382
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36a3fd1579 | ||
|
|
171f63b98c | ||
|
|
c00570c1d1 | ||
|
|
8cfb98ecf5 | ||
|
|
f64282ced3 | ||
|
|
33acb8af82 | ||
|
|
da8851c329 | ||
|
|
31b8859260 | ||
|
|
7321ee31d0 | ||
|
|
cf52cb1586 |
@@ -1,2 +1,2 @@
|
|||||||
web: java -Dserver.port=$PORT $JAVA_OPTS -jar target/share-a-secret-api-1.0.3-SNAPSHOT.jar
|
web: java -Dserver.port=$PORT $JAVA_OPTS -jar target/share-a-secret-api-1.4.0-SNAPSHOT.jar
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>rs.in.zivanovic</groupId>
|
<groupId>rs.in.zivanovic</groupId>
|
||||||
<artifactId>share-a-secret-api</artifactId>
|
<artifactId>share-a-secret-api</artifactId>
|
||||||
<version>1.0.3-SNAPSHOT</version>
|
<version>1.4.0-SNAPSHOT</version>
|
||||||
<name>share-a-secret-api</name>
|
<name>share-a-secret-api</name>
|
||||||
<description>Share-a-Secret REST API service.</description>
|
<description>Share-a-Secret REST API service.</description>
|
||||||
|
|
||||||
@@ -44,6 +44,16 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>rs.in.zivanovic</groupId>
|
||||||
|
<artifactId>sss</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.glxn.qrgen</groupId>
|
||||||
|
<artifactId>javase</artifactId>
|
||||||
|
<version>2.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Marko Zivanovic
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package rs.in.zivanovic.share.a.secret.api;
|
|
||||||
|
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.SecretShare;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author marko
|
|
||||||
*/
|
|
||||||
public final class ShamirSecretSharing {
|
|
||||||
|
|
||||||
public static List<SecretShare> split(String secretString, int total, int threshold) {
|
|
||||||
BigInteger secret = Utils.encodeSecret(secretString);
|
|
||||||
return split(secret, total, threshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<SecretShare> split(BigInteger secretNumber, int total, int threshold) {
|
|
||||||
BigInteger prime = Utils.getFirstPrimeGreaterThan(secretNumber);
|
|
||||||
BigInteger[] coeffs = Utils.generateRandomCoefficients(total, secretNumber, prime);
|
|
||||||
return split(secretNumber, coeffs, total, threshold, prime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<SecretShare> split(BigInteger secret, BigInteger[] coefficients, int total, int threshold,
|
|
||||||
BigInteger prime) {
|
|
||||||
|
|
||||||
if (secret.compareTo(BigInteger.ZERO) <= 0) {
|
|
||||||
throw new IllegalArgumentException("Secret must be positive integer");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prime.compareTo(secret) <= 0) {
|
|
||||||
throw new IllegalArgumentException("Prime must be greater than secret");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coefficients.length < threshold) {
|
|
||||||
throw new IllegalArgumentException("Not enough coefficients, need " + threshold + ", has " +
|
|
||||||
coefficients.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total < threshold) {
|
|
||||||
throw new IllegalArgumentException("Total number of shares must be greater than or equal threshold");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SecretShare> shares = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int i = 1; i <= total; i++) {
|
|
||||||
BigInteger x = BigInteger.valueOf(i);
|
|
||||||
BigInteger v = coefficients[0];
|
|
||||||
for (int c = 1; c < threshold; c++) {
|
|
||||||
v = v.add(x.modPow(BigInteger.valueOf(c), prime).multiply(coefficients[c]).mod(prime)).mod(prime);
|
|
||||||
}
|
|
||||||
shares.add(new SecretShare(i, v, prime));
|
|
||||||
}
|
|
||||||
return shares;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String joinToUtf8String(List<SecretShare> shares) {
|
|
||||||
return Utils.decodeSecret(join(shares));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger join(List<SecretShare> shares) {
|
|
||||||
if (!checkSamePrimes(shares)) {
|
|
||||||
throw new IllegalArgumentException("Shares not from the same series");
|
|
||||||
}
|
|
||||||
BigInteger res = BigInteger.ZERO;
|
|
||||||
for (int i = 0; i < shares.size(); i++) {
|
|
||||||
BigInteger n = BigInteger.ONE;
|
|
||||||
BigInteger d = BigInteger.ONE;
|
|
||||||
BigInteger prime = shares.get(i).getPrime();
|
|
||||||
for (int j = 0; j < shares.size(); j++) {
|
|
||||||
if (i != j) {
|
|
||||||
BigInteger sp = BigInteger.valueOf(shares.get(i).getN());
|
|
||||||
BigInteger np = BigInteger.valueOf(shares.get(j).getN());
|
|
||||||
n = n.multiply(np.negate()).mod(prime);
|
|
||||||
d = d.multiply(sp.subtract(np)).mod(prime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BigInteger v = shares.get(i).getShare();
|
|
||||||
res = res.add(prime).add(v.multiply(n).multiply(d.modInverse(prime))).mod(prime);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkSamePrimes(List<SecretShare> shares) {
|
|
||||||
boolean ret = true;
|
|
||||||
BigInteger prime = null;
|
|
||||||
for (SecretShare share : shares) {
|
|
||||||
if (prime == null) {
|
|
||||||
prime = share.getPrime();
|
|
||||||
} else if (!prime.equals(share.getPrime())) {
|
|
||||||
ret = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShamirSecretSharing() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Marko Zivanovic
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package rs.in.zivanovic.share.a.secret.api;
|
|
||||||
|
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.SecretShare;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author marko
|
|
||||||
*/
|
|
||||||
public final class Utils {
|
|
||||||
|
|
||||||
private static final Random RANDOM = new SecureRandom();
|
|
||||||
private static final byte[] SIGNATURE = "SS".getBytes(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
public static BigInteger encodeSecret(String secret) {
|
|
||||||
byte[] bytes = secret.getBytes(StandardCharsets.UTF_8);
|
|
||||||
byte[] res;
|
|
||||||
if ((bytes[0] & 0b10000000) >> 7 == 1) {
|
|
||||||
res = new byte[bytes.length + 1];
|
|
||||||
res[0] = 0;
|
|
||||||
System.arraycopy(bytes, 0, res, 1, bytes.length);
|
|
||||||
} else {
|
|
||||||
res = bytes;
|
|
||||||
}
|
|
||||||
BigInteger r = new BigInteger(res);
|
|
||||||
assert r.compareTo(BigInteger.ZERO) > 0;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("empty-statement")
|
|
||||||
public static String decodeSecret(BigInteger secret) {
|
|
||||||
byte[] bytes = secret.toByteArray();
|
|
||||||
int count;
|
|
||||||
for (count = 0; count < bytes.length && bytes[count] == 0; count++);
|
|
||||||
byte[] trimmed = new byte[bytes.length - count];
|
|
||||||
System.arraycopy(bytes, count, trimmed, 0, trimmed.length);
|
|
||||||
return new String(trimmed, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger getFirstPrimeGreaterThan(BigInteger secret) {
|
|
||||||
return secret.nextProbablePrime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger getRandomPrimeGreaterThan(BigInteger prime) {
|
|
||||||
BigInteger res = BigInteger.ZERO;
|
|
||||||
while (res.compareTo(prime) <= 0) {
|
|
||||||
res = BigInteger.probablePrime(prime.bitLength(), RANDOM);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger getRandomLessThan(BigInteger prime) {
|
|
||||||
BigInteger r = null;
|
|
||||||
while (r == null || r.compareTo(prime) >= 0) {
|
|
||||||
r = new BigInteger(prime.bitLength(), RANDOM);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger[] generateRandomCoefficients(int n, BigInteger elementZero, BigInteger prime) {
|
|
||||||
BigInteger[] res = new BigInteger[n];
|
|
||||||
res[0] = elementZero;
|
|
||||||
for (int i = 1; i < n; i++) {
|
|
||||||
res[i] = Utils.getRandomLessThan(prime);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] encodeToBinary(SecretShare share) {
|
|
||||||
assert share.getN() >= 0;
|
|
||||||
assert share.getN() <= 255;
|
|
||||||
byte[] shareData = share.getShare().toByteArray();
|
|
||||||
byte[] primeData = share.getPrime().toByteArray();
|
|
||||||
byte n = new Integer(share.getN()).byteValue();
|
|
||||||
|
|
||||||
int len = 9 + SIGNATURE.length + shareData.length + primeData.length;
|
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.allocate(len);
|
|
||||||
bb.put(SIGNATURE);
|
|
||||||
bb.put(n);
|
|
||||||
bb.putInt(shareData.length);
|
|
||||||
bb.put(shareData);
|
|
||||||
bb.putInt(primeData.length);
|
|
||||||
bb.put(primeData);
|
|
||||||
|
|
||||||
assert bb.position() == bb.capacity();
|
|
||||||
assert bb.hasArray();
|
|
||||||
|
|
||||||
return bb.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SecretShare decodeFromBinary(byte[] data) {
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
|
||||||
byte[] signature = new byte[SIGNATURE.length];
|
|
||||||
bb.get(signature);
|
|
||||||
if (!Arrays.equals(SIGNATURE, signature)) {
|
|
||||||
throw new IllegalArgumentException("Invalid data");
|
|
||||||
}
|
|
||||||
byte n = bb.get();
|
|
||||||
int shareDataLen = bb.getInt();
|
|
||||||
byte[] shareData = new byte[shareDataLen];
|
|
||||||
bb.get(shareData);
|
|
||||||
int primeDataLen = bb.getInt();
|
|
||||||
byte[] primeData = new byte[primeDataLen];
|
|
||||||
bb.get(primeData);
|
|
||||||
|
|
||||||
assert bb.position() == bb.capacity();
|
|
||||||
|
|
||||||
BigInteger share = new BigInteger(shareData);
|
|
||||||
BigInteger prime = new BigInteger(primeData);
|
|
||||||
assert share.compareTo(BigInteger.ZERO) > 0;
|
|
||||||
assert prime.compareTo(BigInteger.ZERO) > 0;
|
|
||||||
return new SecretShare(n, share, prime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Utils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright 2014 Marko Zivanovic.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package rs.in.zivanovic.share.a.secret.api.controllers;
|
||||||
|
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import rs.in.zivanovic.share.a.secret.api.dto.SasResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for our controllers. It contains common methods used across different controllers.
|
||||||
|
*
|
||||||
|
* @author Marko Zivanovic <marko@zivanovic.in.rs>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSasController {
|
||||||
|
|
||||||
|
protected SasResponse processValidationErrors(BindingResult br) {
|
||||||
|
SasResponse r = SasResponse.badRequest();
|
||||||
|
br.getFieldErrors().stream().forEach(err -> {
|
||||||
|
r.withInvalidParameterValueError(err.getField(), err.getRejectedValue(), err.getDefaultMessage());
|
||||||
|
});
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright 2014 Marko Zivanovic.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package rs.in.zivanovic.share.a.secret.api.controllers;
|
||||||
|
|
||||||
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import net.glxn.qrgen.core.image.ImageType;
|
||||||
|
import net.glxn.qrgen.javase.QRCode;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import rs.in.zivanovic.share.a.secret.api.dto.SasResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Marko Zivanovic <marko@zivanovic.in.rs>
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/qr")
|
||||||
|
public class QrCodecController extends AbstractSasController {
|
||||||
|
|
||||||
|
private static final List<Integer> VALID_SIZES = Arrays.asList(50, 100, 200, 250);
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.GET, value = "/encode")
|
||||||
|
public ResponseEntity encode(
|
||||||
|
@RequestParam(value = "text", required = true) String text,
|
||||||
|
@RequestParam(value = "size", required = false, defaultValue = "250") int size,
|
||||||
|
@RequestParam(value = "ecl", required = false, defaultValue = "H") ErrorCorrectionLevel ecl) {
|
||||||
|
ResponseEntity response;
|
||||||
|
if (!VALID_SIZES.contains(size)) {
|
||||||
|
response = SasResponse.badRequest().
|
||||||
|
withError(SasResponse.Error.INVALID_PARAMETER_VALUE,
|
||||||
|
"Invalid QR code size, supported sizes: " + VALID_SIZES.toString()).build();
|
||||||
|
} else {
|
||||||
|
ByteArrayOutputStream baos = QRCode.from(text).to(ImageType.JPG).
|
||||||
|
withSize(size, size).withCharset(StandardCharsets.US_ASCII.name()).
|
||||||
|
withErrorCorrection(ecl).stream();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add("Content-Type", "image/jpeg");
|
||||||
|
response = new ResponseEntity<>(baos.toByteArray(), headers, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -37,12 +37,12 @@ import rs.in.zivanovic.share.a.secret.api.dto.SplitResponse;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.SecretShare;
|
|
||||||
import rs.in.zivanovic.share.a.secret.api.ShamirSecretSharing;
|
|
||||||
import rs.in.zivanovic.share.a.secret.api.Utils;
|
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.SasResponse;
|
import rs.in.zivanovic.share.a.secret.api.dto.SasResponse;
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.SplitParameters;
|
import rs.in.zivanovic.share.a.secret.api.dto.SplitParameters;
|
||||||
import rs.in.zivanovic.share.a.secret.api.dto.VersionResponse;
|
import rs.in.zivanovic.share.a.secret.api.dto.VersionResponse;
|
||||||
|
import rs.in.zivanovic.sss.SasUtils;
|
||||||
|
import rs.in.zivanovic.sss.SecretShare;
|
||||||
|
import rs.in.zivanovic.sss.ShamirSecretSharing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -50,7 +50,7 @@ import rs.in.zivanovic.share.a.secret.api.dto.VersionResponse;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/sas")
|
@RequestMapping("/sas")
|
||||||
public class SasController {
|
public class SasController extends AbstractSasController {
|
||||||
|
|
||||||
@Value("${info.build.version:'<N/A>'}")
|
@Value("${info.build.version:'<N/A>'}")
|
||||||
private String version;
|
private String version;
|
||||||
@@ -94,18 +94,10 @@ public class SasController {
|
|||||||
return SasResponse.ok().withData(new VersionResponse(version, buildTime)).build();
|
return SasResponse.ok().withData(new VersionResponse(version, buildTime)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SasResponse processValidationErrors(BindingResult br) {
|
|
||||||
SasResponse r = SasResponse.badRequest();
|
|
||||||
br.getFieldErrors().stream().forEach(err -> {
|
|
||||||
r.withInvalidParameterValueError(err.getField(), err.getRejectedValue(), err.getDefaultMessage());
|
|
||||||
});
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SecretShare> decodeSecretShares(JoinParameters params) {
|
private List<SecretShare> decodeSecretShares(JoinParameters params) {
|
||||||
List<SecretShare> shares = new ArrayList<>(params.getShares().size());
|
List<SecretShare> shares = new ArrayList<>(params.getShares().size());
|
||||||
params.getShares().stream().forEach(share -> {
|
params.getShares().stream().forEach(share -> {
|
||||||
shares.add(Utils.decodeFromBinary(Base64.getDecoder().decode(share)));
|
shares.add(SasUtils.decodeFromBinary(Base64.getDecoder().decode(share)));
|
||||||
});
|
});
|
||||||
return shares;
|
return shares;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Marko Živanović
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package rs.in.zivanovic.share.a.secret.api.dto;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author marko
|
|
||||||
*/
|
|
||||||
public final class SecretShare {
|
|
||||||
|
|
||||||
private final int n;
|
|
||||||
private final BigInteger share;
|
|
||||||
private final BigInteger prime;
|
|
||||||
|
|
||||||
public SecretShare(int n, BigInteger share, BigInteger prime) {
|
|
||||||
this.n = n;
|
|
||||||
this.share = share;
|
|
||||||
this.prime = prime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getN() {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getShare() {
|
|
||||||
return share;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getPrime() {
|
|
||||||
return prime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int hash = 7;
|
|
||||||
hash = 79 * hash + this.n;
|
|
||||||
hash = 79 * hash + Objects.hashCode(this.share);
|
|
||||||
hash = 79 * hash + Objects.hashCode(this.prime);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final SecretShare other = (SecretShare) obj;
|
|
||||||
if (this.n != other.n) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Objects.equals(this.share, other.share)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Objects.equals(this.prime, other.prime)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SecretShare{" + "n=" + n + ", share=" + share + ", prime=" + prime + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -24,9 +24,10 @@
|
|||||||
package rs.in.zivanovic.share.a.secret.api.dto;
|
package rs.in.zivanovic.share.a.secret.api.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.tomcat.util.codec.binary.Base64;
|
import rs.in.zivanovic.sss.SasUtils;
|
||||||
import rs.in.zivanovic.share.a.secret.api.Utils;
|
import rs.in.zivanovic.sss.SecretShare;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -39,7 +40,7 @@ public class SplitResponse {
|
|||||||
public SplitResponse(List<SecretShare> shares) {
|
public SplitResponse(List<SecretShare> shares) {
|
||||||
this.shares.clear();
|
this.shares.clear();
|
||||||
shares.stream().forEachOrdered(share -> {
|
shares.stream().forEachOrdered(share -> {
|
||||||
this.shares.add(Base64.encodeBase64String(Utils.encodeToBinary(share)));
|
this.shares.add(Base64.getUrlEncoder().encodeToString(SasUtils.encodeToBinary(share)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,21 +22,22 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var API_BASE = "https://share-a-secret-api.herokuapp.com/sas";
|
//var API_BASE = "https://share-a-secret-api.herokuapp.com";
|
||||||
|
var API_BASE = "http://localhost:8080";
|
||||||
|
|
||||||
angular.module('sasServices', []).
|
angular.module('sasServices', []).
|
||||||
factory('SasService', ['$resource', function ($resource) {
|
factory('SasService', ['$resource', function ($resource) {
|
||||||
return $resource(API_BASE, {}, {
|
return $resource(API_BASE, {}, {
|
||||||
split: {
|
split: {
|
||||||
url: API_BASE + "/split",
|
url: API_BASE + "/sas/split",
|
||||||
method: "POST"
|
method: "POST"
|
||||||
},
|
},
|
||||||
join: {
|
join: {
|
||||||
url: API_BASE + "/join",
|
url: API_BASE + "/sas/join",
|
||||||
method: "POST"
|
method: "POST"
|
||||||
},
|
},
|
||||||
version: {
|
version: {
|
||||||
url: API_BASE + "/version",
|
url: API_BASE + "/sas/version",
|
||||||
method: "GET"
|
method: "GET"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,10 +32,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" ng-show="shares.length">
|
<div class="row" ng-show="shares.length">
|
||||||
<div class="row">
|
<!--<hr/>-->
|
||||||
<hr/>
|
<h1>Here are your secret shares ...</h1>
|
||||||
<h1>Here are your secret shares ...</h1>
|
<!-- <div class="row">
|
||||||
</div>
|
</div>-->
|
||||||
|
|
||||||
<tabset>
|
<tabset>
|
||||||
<tab>
|
<tab>
|
||||||
@@ -59,6 +59,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</tab>
|
</tab>
|
||||||
|
<tab>
|
||||||
|
<tab-heading><i class="glyphicon glyphicon-qrcode"></i> QR codes</tab-heading>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="text-muted">Use QR encoded shares for easy scanning into mobile devices.</p>
|
||||||
|
<div class="row">
|
||||||
|
<div ng-repeat="share in shares">
|
||||||
|
<div class="col-md-2"><img ng-src="/qr/encode?text={{share}}&size=200&ecl=M"/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tab>
|
||||||
</tabset>
|
</tabset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user