Class: Virgil::Crypto::VirgilCrypto

Inherits:
Object
  • Object
show all
Defined in:
lib/virgil/crypto/virgil_crypto.rb

Overview

Wrapper for cryptographic operations.

Class provides a cryptographic operations in applications, such as hashing, signature generation and verification, key creation, import and export key, encryption and decryption.

Constant Summary collapse

CUSTOM_PARAM_KEY_SIGNATURE =
Bytes.from_string(
  'VIRGIL-DATA-SIGNATURE'
)
CUSTOM_PARAM_KEY_SIGNER_ID =
Bytes.from_string(
  'VIRGIL-DATA-SIGNER-ID'
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_pair_type: KeyPairType::Default) ⇒ VirgilCrypto

Returns a new instance of VirgilCrypto.



46
47
48
# File 'lib/virgil/crypto/virgil_crypto.rb', line 46

def initialize(key_pair_type: KeyPairType::Default)
  @default_key_type = key_pair_type
end

Instance Attribute Details

#use_SHA256_fingerprintsObject

Returns the value of attribute use_SHA256_fingerprints.



44
45
46
# File 'lib/virgil/crypto/virgil_crypto.rb', line 44

def use_SHA256_fingerprints
  @use_SHA256_fingerprints
end

Instance Method Details

#decrypt(cipher_bytes, private_key) ⇒ Bytes

Decrypts the specified bytes using Private key.

Examples:

# You can decrypt data using your private key
include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
plain_data = crypto.decrypt(cipher_data, alice_keys.private_key)

Parameters:

  • cipher_bytes (Bytes)

    encrypted data bytes for decryption.

  • private_key (VirgilPrivateKey)

    private key for decryption.

Returns:

  • (Bytes)

    Decrypted data bytes.

See Also:



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/virgil/crypto/virgil_crypto.rb', line 271

def decrypt(cipher_bytes, private_key)
  cipher_bytes = Validation.check_filled_array_argument!(cipher_bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    decrypted_bytes = cipher.decrypt_with_key(
      cipher_bytes,
      private_key.id,
      private_key.raw_key
    )
    wrap_bytes(decrypted_bytes)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#decrypt_stream(cipher_stream, output_stream, private_key) ⇒ Object

Decrypts the specified stream using Private key.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
File.open('[YOUR_CIPHER_FILE_PATH_HERE]', 'r') do |cipher_stream|
  File.open('[YOUR_DECRYPTED_FILE_PATH_HERE]', 'w') do |decrypted_stream|
    alice_private_key = crypto.import_private_key(exported_private_key)
    crypto.decrypt_stream(cipher_stream, decrypted_stream, alice_private_key)
  end
end

Parameters:

  • cipher_stream (IO)

    readable stream containing encrypted data.

  • output_stream (IO)

    writable stream for output.

  • private_key (VirgilPrivateKey)

    private key for decryption.

See Also:



482
483
484
485
486
487
488
489
490
491
492
# File 'lib/virgil/crypto/virgil_crypto.rb', line 482

def decrypt_stream(cipher_stream, output_stream, private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)
  begin
    cipher = Core::VirgilChunkCipher.new
    source = VirgilStreamDataSource.new(cipher_stream)
    sink = VirgilStreamDataSink.new(output_stream)
    cipher.decrypt_with_key(source, sink, private_key.id, private_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#decrypt_then_verify(bytes, private_key, *public_keys) ⇒ Bytes

Decrypts and verifies the data. for verification,

which can contain signer's public key.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new

alice = crypto.generate_keys
bob = crypto.generate_keys

decrypted_data = crypto.decrypt_then_verify(
  cipher_data,
  bob.private_key,
  alice.public_key
)

Parameters:

Returns:

  • (Bytes)

    Decrypted data bytes.

Raises:

See Also:



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/virgil/crypto/virgil_crypto.rb', line 352

def decrypt_then_verify(bytes, private_key, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    decrypted_bytes = cipher.decrypt_with_key(
      bytes,
      private_key.id,
      private_key.raw_key
    )
    signature = cipher.custom_params.get_data(CUSTOM_PARAM_KEY_SIGNATURE)

    signer_public_key = public_keys.first

    if public_keys.count > 1
      signer_id = cipher.custom_params.get_data(CUSTOM_PARAM_KEY_SIGNER_ID)
      signer_public_key = public_keys.find {|public_key| public_key.id == signer_id}
    end

    is_valid = verify_signature(signature, decrypted_bytes, signer_public_key)
    raise VirgilCryptoException, 'Signature is not valid' unless is_valid

    wrap_bytes(decrypted_bytes)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#encrypt(bytes, *public_keys) ⇒ Bytes

Encrypts the specified data using the specified recipients Public keys. of public keys.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
plain_data = Bytes.from_string('Hello Bob!')
cipher_data = crypto.encrypt(plain_data, alice_keys.public_key)

Parameters:

  • bytes (Virgil::Bytes)

    raw data bytes for encryption.

  • *public_keys (Array<VirgilPublicKey>)

    list

Returns:

  • (Bytes)

    Encrypted bytes.

See Also:



249
250
251
252
253
254
255
256
257
# File 'lib/virgil/crypto/virgil_crypto.rb', line 249

def encrypt(bytes, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)

  begin
    encrypt_for_recipients(bytes, Core::VirgilCipher.new, public_keys)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#encrypt_stream(input_stream, cipher_stream, *public_keys) ⇒ Object

Encrypts the specified stream using public_keys Public keys. public_keys’ public keys. cipher_stream, alice_keys.public_key)

  end
end

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
  File.open('[YOUR_CIPHER_FILE_PATH_HERE]', 'w') do |cipher_stream|
    crypto.encrypt_stream(input_stream,

Parameters:

  • input_stream (IO)

    readable stream containing input bytes.

  • cipher_stream (IO)

    writable stream for output.

  • *public_keys (Array<VirgilPublicKey>)

    list of



452
453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/virgil/crypto/virgil_crypto.rb', line 452

def encrypt_stream(input_stream, cipher_stream, *public_keys)
  begin
    cipher = Core::VirgilChunkCipher.new
    public_keys.each do |public_key|
      public_key = Validation.check_type_argument!(VirgilPublicKey, public_key)
      cipher.add_key_recipient(public_key.id, public_key.raw_key)
    end
    source = VirgilStreamDataSource.new(input_stream)
    sink = VirgilStreamDataSink.new(cipher_stream)
    cipher.encrypt(source, sink)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#export_private_key(private_key, password = nil) ⇒ Bytes

Exports the Private key into material representation.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
exported_private_key = crypto.export_private_key(alice_keys.private_key, 'my_password')

Parameters:

  • private_key (VirgilPrivateKey)

    private key for export.

  • password (String) (defaults to: nil)

    private key password, nil by default.

Returns:

  • (Bytes)

    Private key material representation bytes.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/virgil/crypto/virgil_crypto.rb', line 168

def export_private_key(private_key, password = nil)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    unless password
      return Core::VirgilKeyPair.private_key_to_der(
        private_key.raw_key
      )
    end
    password_bytes = Bytes.from_string(password)
    private_key_bytes = Core::VirgilKeyPair.encrypt_private_key(
      private_key.raw_key,
      password_bytes
    )
    wrap_bytes(
      Core::VirgilKeyPair.private_key_to_der(
        private_key_bytes,
        password_bytes
      )
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#export_public_key(public_key) ⇒ Bytes

Exports the Public key into material representation.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
exported_public_key = crypto.export_public_key(alice_keys.public_key)

Parameters:

Returns:

  • (Bytes)

    Key material representation bytes.



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/virgil/crypto/virgil_crypto.rb', line 201

def export_public_key(public_key)
  public_key = Validation.check_type_argument!(VirgilPublicKey, public_key)

  begin
    wrap_bytes(
      Core::VirgilKeyPair.public_key_to_der(public_key.raw_key)
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#extract_public_key(private_key) ⇒ VirgilPublicKey

Extracts the Public key from Private key. key for extraction.

Parameters:

Returns:



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/virgil/crypto/virgil_crypto.rb', line 217

def extract_public_key(private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    public_key_bytes = Core::VirgilKeyPair.extract_public_key(
      private_key.raw_key,
      []
    )
    VirgilPublicKey.new(
      private_key.id,
      wrap_bytes(
        Core::VirgilKeyPair.public_key_to_der(public_key_bytes)
      )
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_hash(bytes, algorithm = nil) ⇒ Bytes

Computes the hash of specified data and the specified [HashAlgorithm]

Parameters:

  • bytes (Bytes)

    original data bytes to be hashed.

  • algorithm (HashAlgorithm) (defaults to: nil)

    hashing algorithm. The possible values can be found in HashAlgorithm enum.

Returns:

  • (Bytes)

    Hash bytes.



551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/virgil/crypto/virgil_crypto.rb', line 551

def generate_hash(bytes, algorithm = nil)
  bytes = Validation.check_filled_array_argument!(bytes)

  alg = algorithm
  alg ||= use_SHA256_fingerprints ? HashAlgorithm::SHA256 : HashAlgorithm::SHA512

  begin
    native_algorithm = HashAlgorithm.convert_to_native(alg)
    native_hasher = Core::VirgilHash.new(native_algorithm)
    wrap_bytes(native_hasher.hash(bytes))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_keys(keys_type: @default_key_type, key_material: nil) ⇒ KeyPair

Generates asymmetric key pair that is comprised of both public and private keys by specified type. key generation, length must be more than 31.

Examples:

Generated key pair with default type FAST_EC_ED25519

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys

Generated key pair with type EC_SECP256R1

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys(key_type: KeyPairType::EC_SECP256R1)

Parameters:

  • keys_type (Symbol) (defaults to: @default_key_type)

    type of the generated keys. The possible values can be found in KeyPairType enum.

  • key_material (Bytes) (defaults to: nil)

    the only data to be used for

Returns:

  • (KeyPair)

    Generated key pair with the special type.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/virgil/crypto/virgil_crypto.rb', line 73

def generate_keys(keys_type: @default_key_type, key_material: nil)
  key_material = Validation.check_filled_array_argument!(key_material) if key_material
  begin
    native_type = KeyPairType.convert_to_native(keys_type)
    native_key_pair = nil
    native_key_pair = if key_material
                        Core::VirgilKeyPair.generate_from_key_material(
                          native_type,
                          key_material
                        )
                      else
                        Core::VirgilKeyPair.generate(native_type)
                      end
    key_pair_id = compute_public_key_hash(native_key_pair.public_key)
    private_key = VirgilPrivateKey.new(
      key_pair_id,
      wrap_bytes(
        Core::VirgilKeyPair.private_key_to_der(native_key_pair.private_key)
      )
    )
    public_key = VirgilPublicKey.new(
      key_pair_id,
      wrap_bytes(
        Core::VirgilKeyPair.public_key_to_der(native_key_pair.public_key)
      )
    )
    return KeyPair.new(private_key, public_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_signature(bytes, private_key) ⇒ Bytes

Signs the specified data using Private key.

Examples:

Sign the fingerprint of bytes using your private key.

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
# The data to be signed with alice's Private key
data = Bytes.from_string('Hello Bob, How are you?')
signature = crypto.generate_signature(data, alice.private_key)

Parameters:

  • bytes (Bytes)

    raw data bytes for signing.

  • private_key (VirgilPrivateKey)

    private key for signing.

Returns:

  • (Bytes)

    Signature data.

See Also:



394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/virgil/crypto/virgil_crypto.rb', line 394

def generate_signature(bytes, private_key)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilSigner.new(native_algorithm)
    wrap_bytes(signer.sign(bytes, private_key.raw_key))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_stream_signature(input_stream, private_key) ⇒ Bytes

Signs the specified stream using Private key.

@see #verify_stream_signature How to verify the signature

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
    signature = crypto.generate_stream_signature(input_stream, alice_keys.private_key)
end

Parameters:

  • input_stream (IO)

    readable stream containing input data.

  • private_key (VirgilPrivateKey)

    private key for signing.

Returns:

  • (Bytes)

    Signature bytes.



506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/virgil/crypto/virgil_crypto.rb', line 506

def generate_stream_signature(input_stream, private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilStreamSigner.new(native_algorithm)
    source = VirgilStreamDataSource.new(input_stream)
    wrap_bytes(signer.sign(source, private_key.raw_key))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#import_private_key(key_bytes, password = nil) ⇒ VirgilPrivateKey

Imports the Private key from material representation. representation bytes.

Examples:

private_key = crypto.import_private_key(exported_private_key, 'my_password')

Parameters:

  • key_bytes (Bytes)

    private key material

  • password (String) (defaults to: nil)

    private key password, nil by default.

Returns:

See Also:



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/virgil/crypto/virgil_crypto.rb', line 113

def import_private_key(key_bytes, password = nil)
  key_bytes = Validation.check_filled_array_argument!(key_bytes)

  begin
    decrypted_private_key = if !password
                              Core::VirgilKeyPair.private_key_to_der(key_bytes)
                            else
                              Core::VirgilKeyPair.decrypt_private_key(
                                  key_bytes,
                                  Bytes.from_string(password)
                              )
                            end

    public_key_bytes = Core::VirgilKeyPair.extract_public_key(
        decrypted_private_key, []
    )
    key_pair_id = compute_public_key_hash(public_key_bytes)
    private_key_bytes = Core::VirgilKeyPair.private_key_to_der(
        decrypted_private_key
    )
    return VirgilPrivateKey.new(key_pair_id, wrap_bytes(private_key_bytes))
  rescue => error
    raise VirgilCryptoException, error.message
  end

end

#import_public_key(key_bytes) ⇒ VirgilPublicKey

Imports the Public key from material representation. representation bytes.

Examples:

public_key = crypto.import_public_key(exported_public_key)

Parameters:

  • key_bytes (Bytes)

    public key material

Returns:

See Also:



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/virgil/crypto/virgil_crypto.rb', line 147

def import_public_key(key_bytes)
  key_bytes = Validation.check_filled_array_argument!(key_bytes)

  begin
    key_pair_id = compute_public_key_hash(key_bytes)
    public_key_bytes = Core::VirgilKeyPair.public_key_to_der(key_bytes)
    VirgilPublicKey.new(key_pair_id, wrap_bytes(public_key_bytes))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#sign_then_encrypt(bytes, private_key, *public_keys) ⇒ Bytes

Signs and encrypts the data.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new

alice = crypto.generate_keys
bob = crypto.generate_keys

# The data to be signed with alice's Private key
data = Bytes.from_string('Hello Bob, How are you?')
cipher_data = crypto.sign_then_encrypt(
  data,
  alice.private_key,
  bob.public_key
)

Parameters:

  • bytes (Bytes)

    data bytes for signing and encryption.

  • private_key (VirgilPrivateKey)

    private key to sign the data.

  • *public_keys (Array<VirgilPublicKey>)

    list of public keys to encrypt the data.

Returns:

  • (Bytes)

    Signed and encrypted data bytes.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/virgil/crypto/virgil_crypto.rb', line 308

def sign_then_encrypt(bytes, private_key, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    custom_bytes = cipher.custom_params
    custom_bytes.set_data(
      CUSTOM_PARAM_KEY_SIGNATURE,
      generate_signature(bytes, private_key)
    )

    public_key = extract_public_key(private_key)
    custom_bytes.set_data(
      CUSTOM_PARAM_KEY_SIGNER_ID,
      wrap_bytes(public_key.id)
    )
    encrypt_for_recipients(bytes, cipher, public_keys)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#verify_signature(signature, bytes, signer_public_key) ⇒ Boolean

Verifies the specified signature using original data and signer’s public key. key for verification. bytes using Public key.

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
data = Bytes.from_string('Hello Bob, How are you?')
is_valid = crypto.verify_signature(signature, data, alice.public_key)

Examples:

Verify the signature of the fingerprint of

Parameters:

  • bytes (Bytes)

    original data bytes for verification.

  • signature (Bytes)

    signature bytes for verification.

  • signer_public_key (VirgilPublicKey)

    signer public

Returns:

  • (Boolean)

    True if signature is valid, False otherwise.

See Also:



422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/virgil/crypto/virgil_crypto.rb', line 422

def verify_signature(signature, bytes, signer_public_key)
  signature = Validation.check_filled_array_argument!(signature)
  bytes = Validation.check_filled_array_argument!(bytes)
  signer_public_key = Validation.check_type_argument!(VirgilPublicKey, signer_public_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilSigner.new(native_algorithm)
    signer.verify(bytes, signature, signer_public_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end

end

#verify_stream_signature(signature, input_stream, signer_public_key) ⇒ Boolean

Verifies the specified signature using original stream and signer’s Public key.

@see #generate_stream_signature How to get the signature

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
    verified = crypto.verify_stream_signature(signature, input_stream, alice_keys.public_key)
end

Parameters:

  • input_stream (IO)

    readable stream containing input data.

  • signature (Bytes)

    signature bytes for verification.

  • signer_public_key (VirgilPublicKey)

    signer public key for verification.

Returns:

  • (Boolean)

    True if signature is valid, False otherwise.



532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/virgil/crypto/virgil_crypto.rb', line 532

def verify_stream_signature(signature, input_stream, signer_public_key)
  signature = Validation.check_filled_array_argument!(signature)
  signer_public_key = Validation.check_type_argument!(VirgilPublicKey, signer_public_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilStreamSigner.new(native_algorithm)
    source = VirgilStreamDataSource.new(input_stream)
    signer.verify(source, signature, signer_public_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end