You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by is...@apache.org on 2020/11/05 17:08:55 UTC

[airavata-custos] branch develop updated: Adding shamir secret sharing

This is an automated email from the ASF dual-hosted git repository.

isjarana pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git


The following commit(s) were added to refs/heads/develop by this push:
     new aedfab1  Adding shamir secret sharing
     new a10ce8a  Merge pull request #121 from isururanawaka/vault_ssl
aedfab1 is described below

commit aedfab1cdd2bff487c67f6c7bb0aa8a795961747
Author: Isuru Ranawaka <ir...@gmail.com>
AuthorDate: Wed Nov 4 14:53:41 2020 -0500

    Adding shamir secret sharing
---
 .../client/ResourceSecretManagementClient.java     | 27 +++++-
 .../src/main/proto/ResourceSecretService.proto     | 16 ++++
 custos-integration-core/pom.xml                    |  4 +
 .../core/exceptions/InValidParameterException.java | 27 ++++++
 .../core/utils/ShamirSecretHandler.java            | 72 ++++++++++++++++
 .../service/ResourceSecretManagementService.java   | 98 +++++++++++++++++++++-
 pom.xml                                            |  9 ++
 7 files changed, 247 insertions(+), 6 deletions(-)

diff --git a/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java b/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
index a43639a..359356b 100644
--- a/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
+++ b/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
@@ -19,6 +19,7 @@
 
 package org.apache.custos.resource.secret.management.client;
 
+import com.google.protobuf.ByteString;
 import com.google.protobuf.Struct;
 import io.grpc.ManagedChannel;
 import io.grpc.netty.GrpcSslContexts;
@@ -26,6 +27,7 @@ import io.grpc.netty.NettyChannelBuilder;
 import io.grpc.stub.MetadataUtils;
 import org.apache.custos.clients.core.ClientUtils;
 import org.apache.custos.identity.service.GetJWKSRequest;
+import org.apache.custos.integration.core.utils.ShamirSecretHandler;
 import org.apache.custos.resource.secret.management.service.ResourceSecretManagementServiceGrpc;
 import org.apache.custos.resource.secret.service.*;
 
@@ -41,6 +43,9 @@ public class ResourceSecretManagementClient {
 
     private ResourceSecretManagementServiceGrpc.ResourceSecretManagementServiceBlockingStub blockingStub;
 
+    private int defaultNumOfShares = 5;
+    private int defaultThreshold = 3;
+
 
     public ResourceSecretManagementClient(String serviceHost, int servicePort, String clientId,
                                           String clientSecret) throws IOException {
@@ -185,15 +190,29 @@ public class ResourceSecretManagementClient {
      * @param token
      * @return SSHCredential
      */
-    public SSHCredential getSSHCredential(String clientId, String token) {
+    public SSHCredential getSSHCredential(String clientId, String token, boolean useShamirSecret) {
+
         GetResourceCredentialByTokenRequest tokenRequest = GetResourceCredentialByTokenRequest
                 .newBuilder()
                 .setClientId(clientId)
                 .setToken(token)
                 .build();
-
-
-        return blockingStub.getSSHCredential(tokenRequest);
+        if (useShamirSecret) {
+            tokenRequest = tokenRequest.toBuilder()
+                    .setUseShamirsSecretSharingWithEncryption(true)
+                    .setNumOfShares(defaultNumOfShares)
+                    .setThreshold(defaultThreshold)
+                    .build();
+        }
+
+        SSHCredential sshCredential = blockingStub.getSSHCredential(tokenRequest);
+
+        if (useShamirSecret) {
+            List<ByteString> shares = sshCredential.getPrivateKeySharesList();
+            String secret = ShamirSecretHandler.generateSecret(shares, defaultNumOfShares, defaultThreshold);
+            sshCredential = sshCredential.toBuilder().setPrivateKey(secret).build();
+        }
+        return sshCredential;
 
     }
 
diff --git a/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto b/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
index 0ca5a8d..b247990 100644
--- a/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
+++ b/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
@@ -82,11 +82,19 @@ message CertificateCredential {
     string private_key = 5;
     int64 life_time = 6;
     string not_before = 7;
+    bool useShamirsSecretSharingWithEncryption = 8;
+    int32 numOfShares = 9;
+    int32 threshold = 10;
+    repeated bytes  private_key_shares = 11;
 }
 
 message PasswordCredential {
     SecretMetadata metadata = 1;
     string password = 3;
+    bool useShamirsSecretSharingWithEncryption = 4;
+    int32 numOfShares = 5;
+    int32 threshold = 6;
+    repeated bytes  secret_shares = 7;
 }
 
 message SSHCredential {
@@ -94,6 +102,10 @@ message SSHCredential {
     string passphrase = 3;
     string public_key = 4;
     string private_key = 5;
+    bool useShamirsSecretSharingWithEncryption = 6;
+    int32 numOfShares = 7;
+    int32 threshold = 8;
+    repeated bytes  private_key_shares = 9;
 }
 
 
@@ -102,6 +114,10 @@ message GetResourceCredentialByTokenRequest {
     string token = 2;
     string performed_by = 3;
     string client_id = 4;
+    bool useShamirsSecretSharingWithEncryption = 5;
+    int32 numOfShares = 6;
+    int32 threshold = 7;
+
 }
 
 message GetResourceCredentialSummariesRequest {
diff --git a/custos-integration-core/pom.xml b/custos-integration-core/pom.xml
index a7f394c..7fb086d 100644
--- a/custos-integration-core/pom.xml
+++ b/custos-integration-core/pom.xml
@@ -56,6 +56,10 @@
             <groupId>io.grpc</groupId>
             <artifactId>grpc-netty</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.codahale</groupId>
+            <artifactId>shamir</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java b/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java
new file mode 100644
index 0000000..bfd8721
--- /dev/null
+++ b/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied. See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.custos.integration.core.exceptions;
+
+public class InValidParameterException extends RuntimeException {
+
+    public InValidParameterException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java b/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java
new file mode 100644
index 0000000..3ad2374
--- /dev/null
+++ b/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied. See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.custos.integration.core.utils;
+
+import com.codahale.shamir.Scheme;
+import com.google.protobuf.ByteString;
+import org.apache.custos.integration.core.exceptions.InValidParameterException;
+
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ShamirSecretHandler {
+
+    public static Map<Integer, byte[]> splitSecret(String secret, int numOfsplits, int threshold) {
+
+        if (numOfsplits >= threshold) {
+            Scheme scheme = new Scheme(new SecureRandom(), numOfsplits, threshold);
+            byte[] secretArray = secret.getBytes(StandardCharsets.UTF_8);
+            final Map<Integer, byte[]> parts =  scheme.split(secretArray);
+            final Map<Integer, byte[]> selectedParts = new HashMap<>();
+            int count  = 1;
+            for (Integer integer : parts.keySet()){
+                selectedParts.put(integer, parts.get(integer));
+                count ++;
+                if (count == threshold){
+                    break;
+                }
+            }
+            return  selectedParts;
+        } else {
+            throw new
+                    InValidParameterException(
+                    "Cannot split message number of splits should be greater than threshold", null);
+        }
+    }
+
+
+    public static  String generateSecret(List<ByteString> byteStringList, int numOfsplits, int threshold) {
+        Scheme scheme = new Scheme(new SecureRandom(), numOfsplits, threshold);
+        Map<Integer, byte[]> selectedSplits = new HashMap<>();
+        AtomicInteger count = new AtomicInteger();
+        byteStringList.forEach(str-> {
+            selectedSplits.put(count.get(), str.toByteArray());
+            count.getAndIncrement();
+        });
+
+        final byte[] recovered = scheme.join(selectedSplits);
+        return new String(recovered, StandardCharsets.UTF_8);
+    }
+
+}
diff --git a/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java b/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
index ee48a50..8bfd682 100644
--- a/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
+++ b/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
@@ -19,6 +19,7 @@
 
 package org.apache.custos.resource.secret.management.service;
 
+import com.google.protobuf.ByteString;
 import com.google.protobuf.Struct;
 import io.grpc.Status;
 import io.grpc.stub.StreamObserver;
@@ -27,6 +28,7 @@ import org.apache.custos.cluster.management.service.GetServerCertificateRequest;
 import org.apache.custos.cluster.management.service.GetServerCertificateResponse;
 import org.apache.custos.identity.client.IdentityClient;
 import org.apache.custos.identity.service.GetJWKSRequest;
+import org.apache.custos.integration.core.utils.ShamirSecretHandler;
 import org.apache.custos.resource.secret.client.ResourceSecretClient;
 import org.apache.custos.resource.secret.management.service.ResourceSecretManagementServiceGrpc.ResourceSecretManagementServiceImplBase;
 import org.apache.custos.resource.secret.service.*;
@@ -35,6 +37,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.apache.custos.integration.core.utils.ShamirSecretHandler.splitSecret;
+
 @GRpcService
 public class ResourceSecretManagementService extends ResourceSecretManagementServiceImplBase {
 
@@ -128,6 +137,16 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
         LOGGER.debug("Request received to add SSHCredential ");
         try {
 
+            if (request.getUseShamirsSecretSharingWithEncryption()){
+                List<ByteString> byteStringList = request.getPrivateKeySharesList();
+                if (byteStringList != null && byteStringList.size()>0){
+
+                   String secret =  ShamirSecretHandler.
+                           generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+                   request = request.toBuilder().setPrivateKey(secret).build();
+                }
+            }
+
             AddResourceCredentialResponse response = resourceSecretClient.addSSHCredential(request);
 
             responseObserver.onNext(response);
@@ -143,6 +162,15 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
     public void addPasswordCredential(PasswordCredential request, StreamObserver<AddResourceCredentialResponse> responseObserver) {
         LOGGER.debug("Request received to add PasswordCredential ");
         try {
+            if (request.getUseShamirsSecretSharingWithEncryption()){
+                List<ByteString> byteStringList = request.getSecretSharesList();
+                if (byteStringList != null && byteStringList.size()>0){
+
+                    String secret =  ShamirSecretHandler.
+                            generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+                    request = request.toBuilder().setPassword(secret).build();
+                }
+            }
 
             AddResourceCredentialResponse response = resourceSecretClient.addPasswordCredential(request);
             responseObserver.onNext(response);
@@ -158,7 +186,15 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
     public void addCertificateCredential(CertificateCredential request, StreamObserver<AddResourceCredentialResponse> responseObserver) {
         LOGGER.debug("Request received to add CertificateCredential ");
         try {
-
+            if (request.getUseShamirsSecretSharingWithEncryption()){
+                List<ByteString> byteStringList = request.getPrivateKeySharesList();
+                if (byteStringList != null && byteStringList.size()>0){
+
+                    String secret =  ShamirSecretHandler.
+                            generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+                    request = request.toBuilder().setPrivateKey(secret).build();
+                }
+            }
             AddResourceCredentialResponse response = resourceSecretClient.addCertificateCredential(request);
             responseObserver.onNext(response);
             responseObserver.onCompleted();
@@ -175,8 +211,28 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
     public void getSSHCredential(GetResourceCredentialByTokenRequest request, StreamObserver<SSHCredential> responseObserver) {
         LOGGER.debug("Request received to get SSHCredential ");
         try {
-
             SSHCredential response = resourceSecretClient.getSSHCredential(request);
+
+            if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+               int numberOfShares =  response.getNumOfShares();
+               int threshold = response.getThreshold();
+
+               String privateKey =  response.getPrivateKey();
+
+               if (privateKey != null && privateKey.trim().equals("")){
+                  Map<Integer, byte[]>  shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+                  List<ByteString> byteStringList = shares.values().stream().
+                          map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+                 response = response.toBuilder().addAllPrivateKeyShares(byteStringList)
+                         .setPrivateKey("")
+                         .build();
+
+               }
+            }
+
             responseObserver.onNext(response);
             responseObserver.onCompleted();
         } catch (Exception ex) {
@@ -192,6 +248,25 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
         try {
 
             PasswordCredential response = resourceSecretClient.getPasswordCredential(request);
+            if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+                int numberOfShares =  response.getNumOfShares();
+                int threshold = response.getThreshold();
+
+                String privateKey =  response.getPassword();
+
+                if (privateKey != null && privateKey.trim().equals("")){
+                    Map<Integer, byte[]>  shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+                    List<ByteString> byteStringList = shares.values().stream().
+                            map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+                    response = response.toBuilder().addAllSecretShares(byteStringList)
+                            .setPassword("")
+                            .build();
+
+                }
+            }
 
             responseObserver.onNext(response);
             responseObserver.onCompleted();
@@ -208,6 +283,25 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
         try {
 
             CertificateCredential response = resourceSecretClient.getCertificateCredential(request);
+            if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+                int numberOfShares =  response.getNumOfShares();
+                int threshold = response.getThreshold();
+
+                String privateKey =  response.getPrivateKey();
+
+                if (privateKey != null && privateKey.trim().equals("")){
+                    Map<Integer, byte[]>  shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+                    List<ByteString> byteStringList = shares.values().stream().
+                            map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+                    response = response.toBuilder().addAllPrivateKeyShares(byteStringList)
+                            .setPrivateKey("")
+                            .build();
+
+                }
+            }
             responseObserver.onNext(response);
             responseObserver.onCompleted();
         } catch (Exception ex) {
diff --git a/pom.xml b/pom.xml
index 4b810fd..9c2e088 100644
--- a/pom.xml
+++ b/pom.xml
@@ -242,6 +242,13 @@
                 <version>${io.commons.version}</version>
             </dependency>
 
+            <!-- Secret handling dependencies -->
+            <dependency>
+                <groupId>com.codahale</groupId>
+                <artifactId>shamir</artifactId>
+                <version>${com.codahale.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
@@ -527,6 +534,8 @@
 
         <io.commons.version>2.7</io.commons.version>
 
+        <com.codahale.version>0.7.0</com.codahale.version>
+
 
     </properties>