I wanted to use ViteJs. For the purpose, I need to use CryptoJS instead of Crypto. Current code using crypto is working fine.
const crypto = require('crypto');
export function encrypt(plainText, secret) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', secret, iv);
let cipherText;
try {
cipherText = cipher.update(plainText, 'utf8', 'hex');
cipherText += cipher.final('hex');
cipherText = iv.toString('hex') + cipherText
} catch (e) {
cipherText = null;
}
return cipherText;
}
export function decrypt(cipherText, secret) {
const contents = Buffer.from(cipherText, 'hex');
const iv = contents.slice(0, 16);
const textBytes = contents.slice(16);
const decipher = crypto.createDecipheriv('aes-256-cbc', secret, iv);
let decrypted = decipher.update(textBytes, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
Here I want to encrypt on JS and decrypt on Golang. Please help converting the following code to use CryptoJS
The CryptoJS code I tried but didn't work on golang
import CryptoJS from 'crypto-js'
export const encrypt = (plainText: string, secret: string) => {
const iv = CryptoJS.lib.WordArray.random(16)
const encrypted = CryptoJS.AES.encrypt(plainText, secret, {
iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC,
})
return iv + encrypted.toString()
}
export const decrypt = (cipherText: string, secret: string) => {
const iv = cipherText.slice(0, 32)
const ivEx = CryptoJS.enc.Hex.parse(iv)
cipherText = cipherText.replace(iv, '')
const decrypt = CryptoJS.AES.decrypt(cipherText, secret, {
ivEx,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC,
})
return decrypt.toString(CryptoJS.enc.Utf8)
}
Golang code I used to decrypt
// Decrypt decrypts cipher text string into plain text string
func Decrypt(encrypted string, password string) (string, error) {
key := []byte(password)
cipherText, err := hex.DecodeString(encrypted)
if err != nil {
fmt.Printf("%v", err)
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
fmt.Printf("%v", err)
return "", err
}
if len(cipherText) < aes.BlockSize {
return "", errors.New("cipherText too short")
}
iv := cipherText[:aes.BlockSize]
cipherText = cipherText[aes.BlockSize:]
if len(cipherText)%aes.BlockSize != 0 {
return "", errors.New("cipherText is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(cipherText, cipherText)
cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
return fmt.Sprintf("%s", cipherText), nil
}
Related
i have tried to encrypt the folder using aes-256-cbc in nodejs. Encryption works fine but decryption of files shows is error
Error: error:1C800064:Provider routines::bad decrypt at Decipheriv.final (node:internal/crypto/cipher:193:29) at /Users/vikasrushi/ipfs-encryption/utils.js:56:33 at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) { library: 'Provider routines', reason: 'bad decrypt', code: 'ERR_OSSL_BAD_DECRYPT' }
These code i have used to encrypt the files and decryption function throws error. instead of random iv i took constant and for password too. am i missing something
const fs = require("fs");
const algorithm = "aes-256-cbc";
const password = Buffer.from(
"bf3c199c2470cb477d907b1e0917c17bbf3c199c2470cb477d907b1e0917c17b",
"hex"
); // set random encryption key
const iv = Buffer.from("5183666c72eec9e45183666c72eec9e4", "hex"); // set random initialisation vectors
const encryptFolder = (folderPath) => {
// const hash = crypto.createHash("sha256").update(password).digest();
fs.readdir(folderPath, (err, files) => {
if (err) throw err;
// Encrypt each file in the folder
for (const file of files) {
fs.readFile(`${folderPath}/${file}`, (err, data) => {
if (err) throw err;
// Encrypt the data
console.log(iv);
const cipher = crypto.createCipheriv(algorithm, password, iv);
let encrypted = cipher.update(data, "utf8", "hex");
encrypted += cipher.final("hex");
// Write the encrypted data to a new file
fs.writeFile(`./encrypted/${file}.encrypted`, encrypted, (err) => {
if (err) throw err;
});
});
}
});
};
const decryptFolder = (encryptedFolderPath) => {
// const hash = crypto.createHash("sha256").update(password).digest();
// const iv = crypto.randomBytes(16); // not working
// Read the encrypted folder contents
fs.readdir(encryptedFolderPath, (err, encryptedFiles) => {
if (err) throw err;
// Decrypt each file in the folder
for (const encryptedFile of encryptedFiles) {
fs.readFile(
`${encryptedFolderPath}/${encryptedFile}`,
(err, encryptedData) => {
if (err) throw err;
// Decrypt the data
const decipher = crypto.createDecipheriv(algorithm, password, iv);
let decrypted = decipher.update(encryptedData, "hex", "utf8");
decrypted += decipher.final("utf8");
fs.writeFile(
`./decrypted/${encryptedFile.replace(".encrypted", "")}`,
decrypted,
(err) => {
if (err) throw err;
}
);
}
);
}
});
};
module.exports = { encryptFolder, decryptFolder };
In my project I'm using a trigger to create a user document in Firestore when the user signs in. And this is great - everything works perfect for Google Sign-In and Facebook Login.
Here is this trigger:
exports.createAccountDocument = functions.auth.user().onCreate(async user => {
const { uid, displayName } = user
const username = displayName;
const email = user.email || user.providerData[0].email;
const profileImageUrl = uid;
const status = "active";
const str = username;
const qwery = [];
for (let i = 0; i < str.length; ++i) {
qwery[i] = str.substring(0, i + 1).replace(/\s/g, "").toLowerCase();
}
const keywords = qwery;
const bio = "";
return await admin
.firestore()
.collection("users")
.doc(uid)
.set({ bio, email, keywords, profileImageUrl, status, uid, username })
})
For example - this is Facebook Login method:
import SwiftUI
import FBSDKLoginKit
import Firebase
struct FacebookAuthView: UIViewRepresentable {
#Binding var showAnimation: Bool
#Binding var showSheet: Bool
init(showAnimation: Binding<Bool>, showSheet: Binding<Bool>) {
self._showAnimation = showAnimation
self._showSheet = showSheet
}
func makeCoordinator() -> FacebookAuthView.Coordinator {
return FacebookAuthView.Coordinator(showAnimation: self.$showAnimation, showSheet: self.$showSheet)
}
class Coordinator: NSObject, LoginButtonDelegate {
#Binding var showAnimation: Bool
#Binding var showSheet: Bool
init(showAnimation: Binding<Bool>, showSheet: Binding<Bool>) {
self._showAnimation = showAnimation
self._showSheet = showSheet
}
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
if let error = error {
print(error.localizedDescription)
return
}
guard let token = AccessToken.current else {
return
}
self.showAnimation = true
self.showSheet = false
let credential = FacebookAuthProvider.credential(withAccessToken: token.tokenString)
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error, (error as NSError).code == AuthErrorCode.credentialAlreadyInUse.rawValue {
Auth.auth().signIn(with: credential) { result, error in
// continue
print("signIn result: " + authResult!.user.email!)
if let token = firebaseRegistrationPushToken {
checkUserAuthSettings(pushToken: token)
}
}
} else {
// continue
print("Facebook Sign In")
if let token = firebaseRegistrationPushToken {
checkUserAuthSettings(pushToken: token)
}
}
}
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
try! Auth.auth().signOut()
}
}
func makeUIView(context: UIViewRepresentableContext<FacebookAuthView>) -> FBLoginButton {
let view = FBLoginButton()
view.permissions = ["email"]
view.delegate = context.coordinator
return view
}
func updateUIView(_ uiView: FBLoginButton, context: UIViewRepresentableContext<FacebookAuthView>) { }
}
But when I try to create a document when user logs in using Swign in with Apple, this doesn't work. In the Firebase console under Firebase Authentication I can see new the user, but in Firestore, no document shows up at all.
Here is my Sign in with Apple method:
import Foundation
import SwiftUI
import AuthenticationServices
import CryptoKit
import Firebase
struct AppleAuthView: UIViewRepresentable {
#Binding var showAnimation: Bool
#Binding var showSheet: Bool
init(showAnimation: Binding<Bool>, showSheet: Binding<Bool>) {
self._showAnimation = showAnimation
self._showSheet = showSheet
}
func makeCoordinator() -> AppleAuthView.Coordinator {
return AppleAuthView.Coordinator(showAnimation: self.$showAnimation, showSheet: self.$showSheet)
}
class Coordinator: NSObject, ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate {
#Binding var showAnimation: Bool
#Binding var showSheet: Bool
fileprivate var currentNonce: String?
init(showAnimation: Binding<Bool>, showSheet: Binding<Bool>) {
self._showAnimation = showAnimation
self._showSheet = showSheet
super.init()
}
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
let viewController = UIApplication.shared.windows.last?.rootViewController
return (viewController?.view.window!)!
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
guard let nonce = currentNonce else {
fatalError("Invalid state: A login callback was received, but no login request was sent.")
}
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
return
}
let credential = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print(error.localizedDescription)
return
}
print("Apple Sign In")
if let token = firebaseRegistrationPushToken {
checkUserAuthSettings(pushToken: token)
}
}
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
print("Sign in with Apple errored: \(error)")
}
#objc func startSignInWithAppleFlow() {
let nonce = randomNonceString()
currentNonce = nonce
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(nonce)
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
private func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
let charset: Array<Character> = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
var result = ""
var remainingLength = length
while remainingLength > 0 {
let randoms: [UInt8] = (0 ..< 16).map { _ in
var random: UInt8 = 0
let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
if errorCode != errSecSuccess {
fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
}
return random
}
randoms.forEach { random in
if remainingLength == 0 {
return
}
if random < charset.count {
result.append(charset[Int(random)])
remainingLength -= 1
}
}
}
return result
}
#available(iOS 13, *)
private func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
return String(format: "%02x", $0)
}.joined()
return hashString
}
}
func makeUIView(context: Context) -> ASAuthorizationAppleIDButton {
let button = ASAuthorizationAppleIDButton(type: .signIn, style: .black)
button.addTarget(context.coordinator,action: #selector(Coordinator.startSignInWithAppleFlow),for: .touchUpInside)
return button
}
func updateUIView(_ uiView: ASAuthorizationAppleIDButton, context: Context) {
}
}
I don't understand why the document cannot be created. In the console I can see nil.
Please help to fix this issue.
Updated.
Code below - is a simple function to creating user document in firestore in my app
func signup(username: String, email: String, password: String, imageData: Data, completed: #escaping(_ user: User) -> Void, onError: #escaping(_ errorMessage: String) -> Void) {
if !username.isEmpty && !email.isEmpty && !password.isEmpty && !imageData.isEmpty {
AuthService.signupUser(username: username, email: email, password: password, imageData: imageData, onSuccess: completed, onError: onError)
} else {
if username == "" {
errorString = "Please enter your name"
onError(errorString)
// showAlert = true
}
if email == "" {
errorString = "Please enter yor valid email"
onError(errorString)
// showAlert = true
}
if password == "" {
errorString = "Please create password"
onError(errorString)
// showAlert = true
}
if image == Image(IMAGE_USER_PLACEHOLDER) {
errorString = "Please upload your avatar"
onError(errorString)
// showAlert = true
}
}
}
and here is AuthService.signupUser method
static func signupUser(username: String, email: String, password: String, imageData: Data, onSuccess: #escaping(_ user: User) -> Void, onError: #escaping(_ errorMessage: String) -> Void) {
//Firebase.createAccount(username: username, email: email, password: password, imageData: imageData)
Auth.auth().createUser(withEmail: email, password: password) { (authData, error) in
if error != nil {
print(error!.localizedDescription)
onError(error!.localizedDescription)
return
}
guard let userId = authData?.user.uid else { return }
let storageAvatarUserId = Ref.STORAGE_AVATAR_USERID(userId: userId)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
StorageService.saveAvatar(userId: userId, username: username, email: email, imageData: imageData, metadata: metadata, storageAvatarRef: storageAvatarUserId, onSuccess: onSuccess, onError: onError)
}
}
I know that apple sign in cannot take users image & it's ok - my cloud trigger fill this field in document users uid & in my app if user avatar = nil - it's takes universal clipart, It's ok, newer mind.
And this is User file
import Foundation
struct User: Encodable, Decodable {
var uid: String
var email: String
var profileImageUrl: String
var username: String
var bio: String
var keywords: [String]
var status: String?
}
my security rules in firebase are simple, here they are
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
This issue is - that Apple don’t get username.
Issue is solved.
what will be the Key value for my PFX certificate, i am using password as string and then getting error
failed to find any PEM data in certificate input -
Also want to know is there any sample code to pass key,
What would be key for my certificate, as it have only password.
Sample code :
import https from "k6/http";
export let options = {
tlsAuth: [ {
domains: ["example.com"],
cert: open("./TESTGCY.PFX"),
key:'saxobank0'
} ]
};
export default function() {
var url = "url/AooLive/Login.svc";
var payload = JSON.stringify({ UserName: "TESTGCY", Password: "xxxxx" });
var params = { headers: { "Content-Type": "application/json" } }
var res= https.post(url, payload, params);
console.log("Response time was " + String(res.timings.duration) + " ms");
var ses= https.get(url, payload, params);
};
I am implementing a basic encryption/decryption set of functions in nodejs and I keep getting the following error in the decryption part:
Error: Unsupported state or unable to authenticate data
This is my code so far:
import crypto from 'crypto'
import logger from './logger'
const ALGORITHM = 'aes-256-gcm'
export const encrypt = (keyBuffer, dataBuffer, aadBuffer) => {
// iv stands for "initialization vector"
const iv = Buffer.from(crypto.randomBytes(12), 'utf8')
logger.debug('iv: ', iv)
const encryptor = crypto.createCipheriv(ALGORITHM, keyBuffer, iv)
logger.debug('encryptor: ', encryptor)
logger.debug('dataBuffer: ', dataBuffer)
return Buffer.concat([iv, encryptor.update(dataBuffer, 'utf8'), encryptor.final()])
}
export const decrypt = (keyBuffer, dataBuffer, aadBuffer) => {
const iv = dataBuffer.slice(0, 96)
const decryptor = crypto.createDecipheriv(ALGORITHM, keyBuffer, iv)
return Buffer.concat([decryptor.update(dataBuffer.slice(96), 'utf8'), decryptor.final()])
}
My error happens in the last line of the decrypt function. I am storing the iv as part of the dataBuffer.
Thanks in advance!
I realized I had made a couple of mistakes with the original code that I posted, one of them as #TheGreatContini remarked was the size of the slicing which was being done in bits instead of bytes as it should be. Still, the biggest piece that I was missing was the authTag which always should be included in the decipher function setup.
Here is my working code for anybody interested for future references:
import crypto from 'crypto'
import logger from './logger'
const ALGORITHM = 'aes-256-gcm'
export const encrypt = (keyBuffer, dataBuffer, aadBuffer) => {
// iv stands for "initialization vector"
const iv = crypto.randomBytes(12)
const cipher = crypto.createCipheriv(ALGORITHM, keyBuffer, iv)
const encryptedBuffer = Buffer.concat([cipher.update(dataBuffer), cipher.final()])
const authTag = cipher.getAuthTag()
let bufferLength = Buffer.alloc(1)
bufferLength.writeUInt8(iv.length, 0)
return Buffer.concat([bufferLength, iv, authTag, encryptedBuffer])
}
export const decrypt = (keyBuffer, dataBuffer, aadBuffer) => {
const ivSize = dataBuffer.readUInt8(0)
const iv = dataBuffer.slice(1, ivSize + 1)
// The authTag is by default 16 bytes in AES-GCM
const authTag = dataBuffer.slice(ivSize + 1, ivSize + 17)
const decipher = crypto.createDecipheriv(ALGORITHM, keyBuffer, iv)
decipher.setAuthTag(authTag)
return Buffer.concat([decipher.update(dataBuffer.slice(ivSize + 17)), decipher.final()])
}
It's solved finally, you can see my answers below
File Decryption not working in Node when encrypted from php
PHP Code to Encrypt
<?php
$key = "f9036c20bdb656106fd176d260878c63";
$iv = "7152201381f54b46";
exec('openssl enc -aes-256-cbc -K '.$key.' -iv '.$iv.' -in a.txt -out b.txt');
exec('openssl enc -d -aes-256-cbc -K '.$key.' -iv '.$iv.' -in b.txt -out outr.txt');
?>
Decryption works fine in PHP
JS code for Decryption both the below approach is not working
var CryptoJS = require('crypto-js');
var key ="f9036c20bdb656106fd176d260878c63";
var iv1 = "7152201381f54b46";
var text = require('fs').readFileSync('../b.txt');
var bytes = CryptoJS.AES.decrypt(text,key,{iv:iv1, mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7 });
console.log(CryptoJS.enc.Utf8.stringify(bytes));
require('fs').writeFile('../out.txt', CryptoJS.enc.Utf8.stringify(bytes), function (err) {
if (err) {
return console.error(err);
}
});
Also tried with crypto no luck
const crypto = require('crypto');
const fs = require('fs');
var secret = "f9036c20bdb656106fd176d260878c63";
const buf_secret = Buffer.from(secret);
var iv = "7152201381f54b46";
const buf_iv = Buffer.from(iv);
const decipher = crypto.createCipheriv('aes-256-cbc', buf_secret, buf_iv);
decipher.setAutoPadding(true);
fs.readFile('../b.txt', function (err, data) {
if (err) {
return console.log(err);
}
const buf_data = Buffer.from(data);
console.log(buf_data);
let decrypted = decipher.update(buf_data, 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
});
I am sure some padding issue is there, can someone point out what error its having?
It's solved. The problem is PHP openssl accepts key and iv as hex. For openssl256 key length should be 64 and iv length should be 32, but in PHP key length was 32 and iv length was 16 which is for openssl128, so PHP is adding trailing zeros. In JS after adding trailing zeros and considering it as hex its working fine.
const crypto = require('crypto');
const fs = require('fs');
const key_size = 64;
const iv_size = 32;
var secret = "f9036c20bdb656106fd176d260878c63";
secret = pad(secret,key_size,"0"); //pad with trailing zeros
const buf_secret = Buffer.from(secret,'hex');
var iv = "7152201381f54b46";
iv = pad(iv,iv_size,"0");//pad with trailing zeros
const buf_iv = Buffer.from(iv,'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', buf_secret, buf_iv);
decipher.setAutoPadding(true);
const input = fs.createReadStream('../b.txt');
const output = fs.createWriteStream('../decrypted.txt');
input.pipe(decipher).pipe(output);
//content if you want instead of direct writing
//fs.readFile('../b.txt', function (err, data) {
// if (err) {
// return console.log(err);
// }
// const buf_data = Buffer.from(data);
// console.log(buf_data);
// let decrypted = decipher.update(buf_data, 'utf8');
// decrypted += decipher.final('utf8');
// console.log(decrypted);
//
//});
//for padding trailing zeros
function pad(value, width, padchar) {
while (value.length < width) {
value += padchar;
}
return value;
}