All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aliyun.oss.crypto.CryptoModuleBase Maven / Gradle / Ivy

Go to download

The Aliyun OSS SDK for Java used for accessing Aliyun Object Storage Service, includes all service and dependent JARs.

The newest version!
/*
 * 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 com.aliyun.oss.crypto;

import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.CheckedInputStream;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import com.aliyun.oss.model.*;
import org.apache.http.protocol.HTTP;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSEncryptionClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.internal.OSSUtils;
import static com.aliyun.oss.common.utils.CodingUtils.assertParameterNotNull;
import static com.aliyun.oss.common.utils.IOUtils.safeClose;
import static com.aliyun.oss.common.utils.LogUtils.logException;
import static com.aliyun.oss.internal.OSSUtils.OSS_RESOURCE_MANAGER;

public abstract class CryptoModuleBase implements CryptoModule {
    protected static final int DEFAULT_BUFFER_SIZE = 1024 * 2;
    protected final EncryptionMaterials encryptionMaterials;
    protected final CryptoScheme contentCryptoScheme;
    protected final CryptoConfiguration cryptoConfig;
    protected final OSSDirect ossDirect;
    protected final String encryptionClientUserAgent;

    protected CryptoModuleBase(OSSDirect ossDirect,
                                 EncryptionMaterials encryptionMaterials,
                                 CryptoConfiguration cryptoConfig) {
        this.encryptionMaterials = encryptionMaterials;
        this.ossDirect = ossDirect;
        this.cryptoConfig = cryptoConfig;
        this.contentCryptoScheme = getCryptoScheme(cryptoConfig.getContentCryptoMode());
        encryptionClientUserAgent = this.ossDirect.getInnerClientConfiguration().getUserAgent()
                + OSSEncryptionClient.USER_AGENT_SUFFIX;
    }

    private final static CryptoScheme getCryptoScheme(ContentCryptoMode contentCryptoMode) {
        switch (contentCryptoMode) {
        case AES_CTR_MODE:
        default:
            return CryptoScheme.AES_CTR;
        }
    }

    abstract byte[] generateIV();
    abstract CryptoCipher createCryptoCipherFromContentMaterial(ContentCryptoMaterial cekMaterial,
                                                       int cipherMode, long[] cryptoRange, long skipBlock);

    /**
     * Puts the object with data encrypted.
     * 
     * @param req
     *          The put object request.
     * @return the result of the request.
     */
    @Override
    public PutObjectResult putObjectSecurely(PutObjectRequest req) {
        // Update User-Agent.
        setUserAgent(req, encryptionClientUserAgent);

        // Build content crypto material.
        ContentCryptoMaterial cekMaterial = buildContentCryptoMaterials();

        // Update the metadata
        ObjectMetadata meta = updateMetadataWithContentCryptoMaterial(req.getMetadata(), req.getFile(), cekMaterial);
        req.setMetadata(meta);

        // Wraps the object data with a cipher input stream
        final File fileOrig = req.getFile();
        final InputStream isOrig = req.getInputStream();
        PutObjectRequest wrappedReq = wrapPutRequestWithCipher(req, cekMaterial);

        // Put the encrypted object by the oss client
        try {
            return ossDirect.putObject(wrappedReq);
        } finally {
            safeCloseSource(wrappedReq.getInputStream());
            req.setFile(fileOrig);
            req.setInputStream(isOrig);
        }
    }


    // Returns the given {@link PutObjectRequest} instance but has the content as
    // input stream wrapped with a cipher, and configured with some meta data and
    // user metadata.
    protected final PutObjectRequest wrapPutRequestWithCipher(final PutObjectRequest request,
            ContentCryptoMaterial cekMaterial) {
        // Create a new metadata object if there is no metadata already.
        ObjectMetadata metadata = request.getMetadata();
        if (metadata == null) {
            metadata = new ObjectMetadata();
        }

        // update content md5 and length headers.
        updateContentMd5(request, metadata);
        updateContentLength(request, metadata);

        // Create content crypto cipher.
        CryptoCipher cryptoCipher = createCryptoCipherFromContentMaterial(cekMaterial, Cipher.ENCRYPT_MODE, null, 0);

        // Treat all encryption requests as input stream upload requests.
        request.setInputStream(newOSSCryptoCipherInputStream(request, cryptoCipher));

        request.setFile(null);
        return request;
    }

    private void updateContentMd5(final PutObjectRequest request, final ObjectMetadata metadata) {
        if (metadata.getContentMD5() != null) {
            metadata.addUserMetadata(CryptoHeaders.CRYPTO_UNENCRYPTION_CONTENT_MD5, metadata.getContentMD5());
            metadata.removeHeader(OSSHeaders.CONTENT_MD5);
        }

        Map headers = request.getHeaders();
        if (headers.containsKey(OSSHeaders.CONTENT_MD5)) {
            metadata.addUserMetadata(CryptoHeaders.CRYPTO_UNENCRYPTION_CONTENT_MD5, headers.get(OSSHeaders.CONTENT_MD5));
            headers.remove(OSSHeaders.CONTENT_MD5);
        }

        request.setMetadata(metadata);
    }

    private void updateContentLength(final PutObjectRequest request, final ObjectMetadata metadata) {
        final long plaintextLength = plaintextLength(request, metadata);
        if (plaintextLength >= 0) {
            metadata.addUserMetadata(CryptoHeaders.CRYPTO_UNENCRYPTION_CONTENT_LENGTH, Long.toString(plaintextLength));
            metadata.setContentLength(plaintextLength);
        }

        Map headers = request.getHeaders();
        if (headers.containsKey(OSSHeaders.CONTENT_LENGTH)) {
            metadata.addUserMetadata(CryptoHeaders.CRYPTO_UNENCRYPTION_CONTENT_LENGTH, headers.get(OSSHeaders.CONTENT_LENGTH));
        }

        request.setMetadata(metadata);
    }

    /**
     * Checks there an encryption info in the metadata.
     *
     * @param metadata
     *           the object metadata.
     *
     * @return True if has encryption info; False if not.
     */
    public static boolean hasEncryptionInfo(ObjectMetadata metadata) {
        Map userMeta = metadata.getUserMetadata();
        return userMeta != null && userMeta.containsKey(CryptoHeaders.CRYPTO_KEY)
                && userMeta.containsKey(CryptoHeaders.CRYPTO_IV);
    }

    /**
     * Gets the object in OSS, if it was an encrypted object then decrypt it and
     * return the result, otherwise return the object directly.
     *
     * @param req The {@link GetObjectRequest} instance.
     * @return  The {@link OSSObject} instance.
     */
    @Override
    public OSSObject getObjectSecurely(GetObjectRequest req) {
        // Update User-Agent.
        setUserAgent(req, encryptionClientUserAgent);
        
        // Adjust range-get
        long[] desiredRange = req.getRange();
        long[] adjustedCryptoRange = getAdjustedCryptoRange(desiredRange);
        if (adjustedCryptoRange != null) {
            req.setRange(adjustedCryptoRange[0], adjustedCryptoRange[1]);
        }

        // Get the object from OSS
        OSSObject retrieved = ossDirect.getObject(req);

        // Recheck range-get
        String contentRange = (String) retrieved.getObjectMetadata().getRawMetadata().get("Content-Range");
        if (contentRange == null && adjustedCryptoRange != null) {
            desiredRange[0] = 0;
            desiredRange[1] = retrieved.getObjectMetadata().getContentLength() - 1;
            adjustedCryptoRange = desiredRange.clone();
        }

        // Convert OSSObject content with cipher insteam
        try {
            if (hasEncryptionInfo(retrieved.getObjectMetadata())) {
                return decipherWithMetadata(req, desiredRange, adjustedCryptoRange, retrieved);
            }
            OSSObject adjustedOSSObject = adjustToDesiredRange(retrieved, desiredRange);
            return adjustedOSSObject;
        } catch (Exception e) {
            safeCloseSource(retrieved);
            throw new ClientException(e);
        }
    }

    // Decrypt the encypted object by the metadata achieved.
    protected OSSObject decipherWithMetadata(GetObjectRequest req,
            long[] desiredRange,
            long[] cryptoRange, OSSObject retrieved) {

        // Create ContentCryptoMaterial by parse metadata.
        ContentCryptoMaterial cekMaterial = createContentMaterialFromMetadata(retrieved.getObjectMetadata());

        // Create crypto cipher by contentCryptoMaterial
        CryptoCipher cryptoCipher = createCryptoCipherFromContentMaterial(cekMaterial, Cipher.DECRYPT_MODE, cryptoRange,
                0);

        // Wrap retrieved object with cipherInputStream.
        InputStream objectContent = retrieved.getObjectContent();
        retrieved.setObjectContent(
                new CipherInputStream(objectContent,
                    cryptoCipher,
                    DEFAULT_BUFFER_SIZE));

        // Adjust the output to the desired range of bytes.
        OSSObject adjusted = adjustToDesiredRange(retrieved, desiredRange);
        return adjusted;
    }

    protected void safeCloseSource(Closeable is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException ex) {
            }
        }
    }

    // Adjusts the retrieved OSSObject so that the object contents contain only the
    // range of bytes desired by the user. Since encrypted contents can only be
    // retrieved in CIPHER_BLOCK_SIZE (16 bytes) chunks, the OSSObject potentially
    // contains more bytes than desired, so this method adjusts the contents range.
    protected final OSSObject adjustToDesiredRange(OSSObject OSSobject, long[] range) {
        if (range == null)
            return OSSobject;

        try {
            InputStream objectContent = OSSobject.getObjectContent();
            InputStream adjustedRangeContents = new AdjustedRangeInputStream(objectContent, range[0], range[1]);
            OSSobject.setObjectContent(adjustedRangeContents);
            return OSSobject;
        } catch (IOException e) {
            throw new ClientException("Error adjusting output to desired byte range: " + e.getMessage());
        }
    }

    private void checkMultipartContext(MultipartUploadCryptoContext context) {
        if (context == null) {
            throw new IllegalArgumentException("MultipartUploadCryptoContext should not be null.");
        }

        if (0 != (context.getPartSize() % CryptoScheme.BLOCK_SIZE) || context.getPartSize() <= 0) {
            throw new IllegalArgumentException("MultipartUploadCryptoContext part size is not 16 bytes alignment.");
        }
    }

    /**
     * Gets the object in OSS and write it in a file, if it was an encrypted object
     * then decrypt it, otherwise wirte the object directly.
     * @param getObjectRequest The {@link GetObjectRequest} instance.
     * @param file The {@link File} instance to write into.
     * @return  The {@link ObjectMetadata} instance.
     */
    @Override
    public ObjectMetadata getObjectSecurely(GetObjectRequest getObjectRequest, File file) {
        assertParameterNotNull(file, "file");
        OSSObject ossObject = getObjectSecurely(getObjectRequest);
        OutputStream outputStream = null;
        try {
            outputStream = new BufferedOutputStream(new FileOutputStream(file));
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = IOUtils.readNBytes(ossObject.getObjectContent(), buffer, 0, buffer.length)) > 0) {
                outputStream.write(buffer, 0, bytesRead);
            }

            if (ossDirect.getInnerClientConfiguration().isCrcCheckEnabled() && getObjectRequest.getRange() == null) {
                Long clientCRC = null;
                InputStream contentInputStream = ossObject.getObjectContent();
                if (contentInputStream instanceof CipherInputStream) {
                    InputStream subStream = ((CipherInputStream) contentInputStream).getDelegateStream();
                    if (subStream instanceof CheckedInputStream){
                        clientCRC = ((CheckedInputStream) subStream).getChecksum().getValue();
                    }
                }
                else {
                    clientCRC = IOUtils.getCRCValue(ossObject.getObjectContent());
                }
                OSSUtils.checkChecksum(clientCRC, ossObject.getServerCRC(), ossObject.getRequestId());
            }
            return ossObject.getObjectMetadata();
        } catch (IOException ex) {
            logException("Cannot read object content stream: ", ex);
            throw new ClientException(OSS_RESOURCE_MANAGER.getString("CannotReadContentStream"), ex);
        } finally {
            safeClose(outputStream);
            safeClose(ossObject.getObjectContent());
        }
    }

    /**
     * Initiates the multipart upload request, and bulid the crypto context.
     * @param req
     *         The {@link InitiateMultipartUploadRequest} instance.
     * @param context
     *         The multi part crypto context contains the content crypto materials and
     *         upload information, it should created on the outside with part-size and data-size set done, the 
     *         content crypto materials and other upload information will be filled after initiate request done.
     * @return  The {@link InitiateMultipartUploadResult} instance.
     */
    @Override
    public InitiateMultipartUploadResult initiateMultipartUploadSecurely(InitiateMultipartUploadRequest req,
            MultipartUploadCryptoContext context) {
        checkMultipartContext(context);

        // Update User-Agent.
        setUserAgent(req, encryptionClientUserAgent);

        // Get content crypto material.
        ContentCryptoMaterial cekMaterial = buildContentCryptoMaterials();

        ObjectMetadata metadata = req.getObjectMetadata();
        if (metadata == null) {
            metadata = new ObjectMetadata();
        }

        // Store encryption info in metadata
        metadata = updateMetadataWithContentCryptoMaterial(metadata, null, cekMaterial);
        metadata = updateMetadataWithUploadContext(metadata, context);
        req.setObjectMetadata(metadata);

        // Fill context
        InitiateMultipartUploadResult result = ossDirect.initiateMultipartUpload(req);
        context.setUploadId(result.getUploadId());
        context.setContentCryptoMaterial(cekMaterial);

        return result;
    }

    /**
     * Uploads the part secured.
     * @param req
     *         The {@link UploadPartRequest} instance.
     * @param context
     *         The multi part crypto context contains the content crypto materials and
     *         upload information, it should created on the outside with part-size and data-size set done, the
     *         content crypto materials and other upload information will be filled after initiate request done.
     * @return  The {@link UploadPartResult} instance.
     */
    @Override
    public UploadPartResult uploadPartSecurely(UploadPartRequest req, MultipartUploadCryptoContext context) {
        final UploadPartResult result;

        // Check partsize and context
        checkMultipartContext(context);
        if (!context.getUploadId().equals(req.getUploadId())) {
            throw new ClientException("The multipartUploadCryptoContextcontext input upload id is invalid."
                    + "context uploadid:" + context.getUploadId() + ",uploadRequest uploadid:" + req.getUploadId());
        }

        // Update User-Agent.
        setUserAgent(req, encryptionClientUserAgent);

        // Create CryptoCipher
        long offset = context.getPartSize() * (req.getPartNumber() - 1);
        long skipBlock = offset / CryptoScheme.BLOCK_SIZE;
        CryptoCipher cryptoCipher = createCryptoCipherFromContentMaterial(context.getContentCryptoMaterial(),
                Cipher.ENCRYPT_MODE, null, skipBlock);
        // Wrap InputStram to CipherInputStream
        final InputStream isOrig = req.getInputStream();
        CipherInputStream isCurr = null;
        try {
            isCurr = new RenewableCipherInputStream(isOrig, cryptoCipher, DEFAULT_BUFFER_SIZE);
            req.setInputStream(isCurr);
            result = ossDirect.uploadPart(req);
        } finally {
            safeCloseSource(isCurr);
            req.setInputStream(isOrig);
        }
        return result;
    }

    // Wraps the inputStream with an crypto cipher.
    private CipherInputStream newOSSCryptoCipherInputStream(PutObjectRequest req, CryptoCipher cryptoCipher) {
        final File fileOrig = req.getFile();
        final InputStream isOrig = req.getInputStream();
        InputStream isCurr = isOrig;
        try {
            if (fileOrig != null) {
                isCurr = new FileInputStream(fileOrig);
            }
            return new RenewableCipherInputStream(isCurr, cryptoCipher, DEFAULT_BUFFER_SIZE);
        } catch (Exception e) {
            safeCloseSource(isCurr);
            req.setFile(fileOrig);
            req.setInputStream(isOrig);
            throw new ClientException("Unable to create cipher input stream." + e.getMessage(), e);
        }
    }

    // Returns the plaintext length from the request and metadata; or -1 if unknown.
    protected final long plaintextLength(PutObjectRequest request, ObjectMetadata metadata) {
        if (request.getFile() != null) {
            return request.getFile().length();
        } else if (request.getInputStream() != null && metadata.getRawMetadata().get("Content-Length") != null) {
            return metadata.getContentLength();
        }
        return -1;
    }

    // Adjustes the range-get start offset to allgn with cipher block.
    long[] getAdjustedCryptoRange(long[] range) {
        if (range == null) {
            return null;
        }

        if ((range[0] > range[1]) || (range[0] < 0) || (range[1] <= 0)) {
            throw new ClientException("Your input get-range is illegal. + range:" + range[0] + "~" + range[1]);
        }

        long[] adjustedCryptoRange = new long[2];
        adjustedCryptoRange[0] = getCipherBlockLowerBound(range[0]);
        adjustedCryptoRange[1] = range[1];
        return adjustedCryptoRange;
    }

    private long getCipherBlockLowerBound(long leftmostBytePosition) {
        long cipherBlockSize = CryptoScheme.BLOCK_SIZE;
        long offset = leftmostBytePosition % cipherBlockSize;
        long lowerBound = leftmostBytePosition - offset;
        return lowerBound;
    }

    // Build a new content crypto material read-only.
    protected final ContentCryptoMaterial buildContentCryptoMaterials() {
        // Generate random CEK IV
        byte[] iv = generateIV();
        SecretKey cek = generateCEK();

        // Build content crypto Materials by encryptionMaterials.
        ContentCryptoMaterialRW contentMaterialRW = new ContentCryptoMaterialRW();
        contentMaterialRW.setIV(iv);
        contentMaterialRW.setCEK(cek);
        contentMaterialRW.setContentCryptoAlgorithm(contentCryptoScheme.getContentChiperAlgorithm());
        encryptionMaterials.encryptCEK(contentMaterialRW);

        return contentMaterialRW;
    }

    // Add the upload part info into metadata.
    protected final ObjectMetadata updateMetadataWithUploadContext(ObjectMetadata metadata,
            MultipartUploadCryptoContext context) {
        if (metadata == null) {
            metadata = new ObjectMetadata();
        }
        metadata.addUserMetadata(CryptoHeaders.CRYPTO_PART_SIZE, String.valueOf(context.getPartSize()));
        if (context.getDataSize() > 0) {
            metadata.addUserMetadata(CryptoHeaders.CRYPTO_DATA_SIZE, String.valueOf(context.getDataSize()));
        }
        return metadata;
    }

    // Storages the encrytion materials in the object metadata.
    protected final ObjectMetadata updateMetadataWithContentCryptoMaterial(ObjectMetadata metadata, File file,
            ContentCryptoMaterial contentCryptoMaterial) {
        if (metadata == null)
            metadata = new ObjectMetadata();
        if (file != null) {
            Mimetypes mimetypes = Mimetypes.getInstance();
            metadata.setContentType(mimetypes.getMimetype(file));
        }
        // Put the encrypted content encrypt key into the object meatadata
        byte[] encryptedCEK = contentCryptoMaterial.getEncryptedCEK();
        metadata.addUserMetadata(CryptoHeaders.CRYPTO_KEY, BinaryUtil.toBase64String(encryptedCEK));

        // Put the iv into the object metadata
        byte[] encryptedIV = contentCryptoMaterial.getEncryptedIV();
        metadata.addUserMetadata(CryptoHeaders.CRYPTO_IV, BinaryUtil.toBase64String(encryptedIV));

        // Put the content encrypt key algorithm into the object metadata
        String contentCryptoAlgo = contentCryptoMaterial.getContentCryptoAlgorithm();
        metadata.addUserMetadata(CryptoHeaders.CRYPTO_CEK_ALG, contentCryptoAlgo);

        // Put the key wrap algorithm into the object metadata
        String keyWrapAlgo = contentCryptoMaterial.getKeyWrapAlgorithm();
        metadata.addUserMetadata(CryptoHeaders.CRYPTO_WRAP_ALG, keyWrapAlgo);

        // Put the crypto description into the object metadata
        Map materialDesc = contentCryptoMaterial.getMaterialsDescription();
        if (materialDesc != null && materialDesc.size() > 0) {
            try {
                JSONObject descJson = new JSONObject(materialDesc);
                String descStr = descJson.toString();
                metadata.addUserMetadata(CryptoHeaders.CRYPTO_MATDESC, descStr);
            } catch (Exception e) {
            }
        }

        return metadata;
    }

    // Builds a new content crypto material for decrypting the object achieved.
    protected ContentCryptoMaterial createContentMaterialFromMetadata(ObjectMetadata meta) {
        Map userMeta = meta.getUserMetadata();
        // Encrypted CEK and encrypted IV.
        String b64CEK = userMeta.get(CryptoHeaders.CRYPTO_KEY);
        String b64IV = userMeta.get(CryptoHeaders.CRYPTO_IV);
        if (b64CEK == null || b64IV == null) {
            throw new ClientException("Content encrypted key  or encrypted iv not found.");
        }
        byte[] encryptedCEK = BinaryUtil.fromBase64String(b64CEK);
        byte[] encryptedIV = BinaryUtil.fromBase64String(b64IV);

        // Key wrap algorithm
        final String keyWrapAlgo = userMeta.get(CryptoHeaders.CRYPTO_WRAP_ALG);
        if (keyWrapAlgo == null)
            throw new ClientException("Key wrap algorithm should not be null.");

        // CEK algorithm
        String cekAlgo = userMeta.get(CryptoHeaders.CRYPTO_CEK_ALG);

        // Description
        String mateDescString = userMeta.get(CryptoHeaders.CRYPTO_MATDESC);
        Map matDesc = getDescFromJsonString(mateDescString);

        // Decrypt the secured CEK to CEK.
        ContentCryptoMaterialRW contentMaterialRW = new ContentCryptoMaterialRW();
        contentMaterialRW.setEncryptedCEK(encryptedCEK);
        contentMaterialRW.setEncryptedIV(encryptedIV);
        contentMaterialRW.setMaterialsDescription(matDesc);
        contentMaterialRW.setContentCryptoAlgorithm(cekAlgo);
        contentMaterialRW.setKeyWrapAlgorithm(keyWrapAlgo);
        encryptionMaterials.decryptCEK(contentMaterialRW);

        // Convert to read-only object.
        return contentMaterialRW;
    }

    // return the corresponding material description from the given json string.
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected static Map getDescFromJsonString(String jsonString) {
        Map map = new HashMap();
        if (jsonString == null) {
            return map;
        }
        try {
            JSONObject obj = new JSONObject(jsonString);
            Iterator iter = obj.keys();
            while (iter.hasNext()) {
                String key = (String) iter.next();
                String value = obj.getString(key);
                map.put(key, value);
            }
            return map;
        } catch (JSONException e) {
            throw new ClientException("Unable to parse Json string:" + "json", e);
        }
    }

    // Returns a srcret key for encrypting content.
    protected SecretKey generateCEK() {
        KeyGenerator generator;
        final String keygenAlgo = contentCryptoScheme.getKeyGeneratorAlgorithm();
        final int keyLength = contentCryptoScheme.getKeyLengthInBits();
        try {
            generator = KeyGenerator.getInstance(keygenAlgo);
            generator.init(keyLength, cryptoConfig.getSecureRandom());
            SecretKey secretKey = generator.generateKey();
            for (int retry = 0; retry < 9; retry++) {
                secretKey = generator.generateKey();
                if (secretKey.getEncoded()[0] != 0)
                    return secretKey;
            }
            throw new ClientException("Failed to generate secret key");
        } catch (NoSuchAlgorithmException e) {
            throw new ClientException("No such algorithm:" + keygenAlgo + ", " + e.getMessage(), e);
        }
    }

    protected void setUserAgent(WebServiceRequest req, String userAgent) {
        req.addHeader(HTTP.USER_AGENT, userAgent);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy