diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json
index f23838522a8a7bf23ddd751b64ee31e802f6738c..1cf2efc691f08cbf39d10bfb04e53fc560053231 100644
--- a/www/i18n/locale-en-GB.json
+++ b/www/i18n/locale-en-GB.json
@@ -518,6 +518,9 @@
       "BTN_RESET" : "Reset",
       "DOWNLOAD_REVOKE": "Save a revocation file",
       "DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
+      "GENERATE_KEYFILE": "Generate my keychain file ...",
+      "GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
+      "KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Register as member...",
       "MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
       "SEND_IDENTITY": "Publish identity...",
@@ -556,7 +559,23 @@
       "SAVE_ID": "Save my credentials...",
       "SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
       "STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
-      "TITLE": "Account and security"
+      "TITLE": "Account and security",
+      "KEYFILE": {
+        "PUBSEC_FORMAT": "PubSec format.",
+        "PUBSEC_FORMAT_HELP": "This file format is compatible in particular with Cesium and Gannonce. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
+        "WIF_FORMAT": "Wallet Import Format (WIF)",
+        "WIF_FORMAT_HELP": "This format is used in particular by paper wallets. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
+        "EWIF_FORMAT": "Encrypted Wallet Import Format (WIF)",
+        "EWIF_FORMAT_HELP": "This format is used in particular by paper wallets. However, <b>the keychain is encrypted</b> from a passphrase of your choice.",
+        "PASSWORD_POPUP": {
+          "TITLE": "Keychain file encrypted",
+          "HELP": "Please enter the passphrase:",
+          "PASSWORD_HELP": "Passphrase"
+        },
+        "ERROR": {
+          "BAD_PASSWORD": "Bad passphrase"
+        }
+      }
     },
     "FILE_NAME": "{{currency}} - Account statement {{pubkey|formatPubkey}} to {{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
@@ -582,9 +601,12 @@
     }
   },
   "ERROR": {
+    "UNKNOWN_URI_FORMAT": "Unknown URI format",
+    "PUBKEY_INVALID_CHECKSUM": "Invalid public key (bad checksum).",
     "POPUP_TITLE": "Error",
     "UNKNOWN_ERROR": "Unknown error",
     "CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.",
+    "DOWNLOAD_KEYFILE_FAILED": "Failed to generate the keychain file.",
     "EQUALS_TO_PSEUDO": "Must be different from pseudonym",
     "EQUALS_TO_SALT": "Must be different from secret identifier",
     "FIELD_REQUIRED": "This field is required.",
@@ -634,6 +656,7 @@
     "INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.",
     "INVALID_COMMENT": "Field 'reference' has a bad format.",
     "INVALID_PUBKEY": "Public key has a bad format.",
+    "INVALID_PUBKEY_CHECKSUM": "Invalid checksum.",
     "IDENTITY_REVOKED": "This identity <b>has been revoked {{revocationTime|formatFromNow}}</b> ({{revocationTime|formatDate}}). It can no longer become a member.",
     "IDENTITY_PENDING_REVOCATION": "The <b>revocation of this identity</b> has been requested and is awaiting processing. Certification is therefore disabled.",
     "IDENTITY_INVALID_BLOCK_HASH": "This membership application is no longer valid (because it references a block that network peers are cancelled): the person must renew its application for membership <b>before</b> being certified.",
diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json
index ce6a86f8565a36770a375354d66c139e78f77844..48f0eee6ad456675e515222ff63d1ab4a8a36d0d 100644
--- a/www/i18n/locale-en.json
+++ b/www/i18n/locale-en.json
@@ -518,6 +518,9 @@
       "BTN_RESET" : "Reset",
       "DOWNLOAD_REVOKE": "Save a revocation file",
       "DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
+      "GENERATE_KEYFILE": "Generate my keychain file ...",
+      "GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
+      "KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Register as member...",
       "MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
       "SEND_IDENTITY": "Publish identity...",
@@ -556,7 +559,23 @@
       "SAVE_ID": "Save my credentials...",
       "SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
       "STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
-      "TITLE": "Account and security"
+      "TITLE": "Account and security",
+      "KEYFILE": {
+        "PUBSEC_FORMAT": "PubSec format.",
+        "PUBSEC_FORMAT_HELP": "This file format is compatible in particular with Cesium and Gannonce. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
+        "WIF_FORMAT": "Wallet Import Format (WIF)",
+        "WIF_FORMAT_HELP": "This format is used in particular by paper wallets. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
+        "EWIF_FORMAT": "Encrypted Wallet Import Format (WIF)",
+        "EWIF_FORMAT_HELP": "This format is used in particular by paper wallets. However, <b>the keychain is encrypted</b> from a passphrase of your choice.",
+        "PASSWORD_POPUP": {
+          "TITLE": "Keychain file encrypted",
+          "HELP": "Please enter the passphrase:",
+          "PASSWORD_HELP": "Passphrase"
+        },
+        "ERROR": {
+          "BAD_PASSWORD": "Bad passphrase"
+        }
+      }
     },
     "FILE_NAME": "{{currency}} - Account statement {{pubkey|formatPubkey}} to {{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
@@ -582,9 +601,12 @@
     }
   },
   "ERROR": {
+    "UNKNOWN_URI_FORMAT": "Unknown URI format",
+    "PUBKEY_INVALID_CHECKSUM": "Invalid public key (bad checksum).",
     "POPUP_TITLE": "Error",
     "UNKNOWN_ERROR": "Unknown error",
     "CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.",
+    "DOWNLOAD_KEYFILE_FAILED": "Failed to generate the keychain file.",
     "EQUALS_TO_PSEUDO": "Must be different from pseudonym",
     "EQUALS_TO_SALT": "Must be different from secret identifier",
     "FIELD_REQUIRED": "This field is required.",
@@ -634,6 +656,7 @@
     "INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.",
     "INVALID_COMMENT": "Field 'reference' has a bad format.",
     "INVALID_PUBKEY": "Public key has a bad format.",
+    "INVALID_PUBKEY_CHECKSUM": "Invalid checksum.",
     "IDENTITY_REVOKED": "This identity <b>has been revoked {{revocationTime|formatFromNow}}</b> ({{revocationTime|formatDate}}). It can no longer become a member.",
     "IDENTITY_PENDING_REVOCATION": "The <b>revocation of this identity</b> has been requested and is awaiting processing. Certification is therefore disabled.",
     "IDENTITY_INVALID_BLOCK_HASH": "This membership application is no longer valid (because it references a block that network peers are cancelled): the person must renew its application for membership <b>before</b> being certified.",
diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json
index 90739250c16c41a33fd5c7937501f14ffb1c9ecf..61a938df059814bb624ab1fd3b6fdb1a26a79644 100644
--- a/www/i18n/locale-fr-FR.json
+++ b/www/i18n/locale-fr-FR.json
@@ -423,7 +423,7 @@
       "TYPE" : "Type :",
       "SIZE": "Taille :",
       "VALIDATING": "Validation en cours...",
-      "HELP": "Format de fichier attendu : <b>.dunikey</b> (type PubSec). D'autres formats sont en cours de développement (EWIF, WIF)."
+      "HELP": "Format de fichier attendu : <b>.yml</b> ou <b>.dunikey</b> (type PubSec, WIF ou EWIF)."
     }
   },
   "AUTH": {
@@ -519,7 +519,7 @@
       "DOWNLOAD_REVOKE": "Sauvegarder mon fichier de révocation",
       "DOWNLOAD_REVOKE_HELP": "Disposer d'un fichier de révocation est important, par exemple en cas de perte de vos identifiants. Il vous permet de <b>sortir ce compte de la toile de confiance</b>, en redevenant ainsi un simple portefeuille.",
       "GENERATE_KEYFILE": "Générer mon fichier de trousseau...",
-      "GENERATE_KEYFILE_HELP": "Génère un fichier permettant de vous authentifier sans saisir vos identifiants.<br/><b>Attention :</b> ce fichier contiendra votre clef secrète : il est donc très important de le mettre en lieu sûr !",
+      "GENERATE_KEYFILE_HELP": "Génère un fichier permettant de vous authentifier sans saisir vos identifiants.<br/><b>Attention :</b> ce fichier contiendra votre trousseau de compte (clefs publique et secrète) ; Il est donc très important de le mettre en lieu sûr !",
       "KEYFILE_FILENAME": "trousseau-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Transformer en compte membre...",
       "MEMBERSHIP_IN_HELP": "Permet de <b>transformer</b> un compte simple portefeuille <b>en compte membre</b>, en envoyant une demande d'adhésion. Utile uniquement si vous n'avez pas déjà une autre compte membre.",
@@ -562,15 +562,18 @@
       "TITLE": "Compte et sécurité",
       "KEYFILE": {
         "PUBSEC_FORMAT": "Format PubSec.",
-        "PUBSEC_FORMAT_HELP": "Ce format de fichier est compatible notamment avec Cesium et gannonce.",
-        "WIF_FORMAT": "Format WIF",
-        "WIF_FORMAT_HELP": "Ce format permet notamment la génération de portefeuilles papier (Paper Wallet).",
-        "EWIF_FORMAT": "Format EWIF",
-        "EWIF_FORMAT_HELP": "Ce format protège le trousseau par un mot de passe. Il permet notamment la génération de portefeuilles papier (Paper Wallet).",
+        "PUBSEC_FORMAT_HELP": "Ce format votre stocke votre trousseau de manière très simple. Il est compatible notamment avec Cesium, ğannonce et Duniter.<br/><b>Attention:</b>Le fichier <b>n'est pas chiffré</b> (la clef secrète y apparait en clair); Veuillez donc le stocker en lieu sûr !",
+        "WIF_FORMAT": "Format WIF (Wallet Import Format) - v1",
+        "WIF_FORMAT_HELP": "Ce format stocke votre votre trousseau, en y intégrant une somme de contrôle pour vérifier l'intégrité du fichier. Il est compatible notamment avec les portefeuilles papier (Duniter paper wallet).<br/><b>Attention:</b>Le fichier <b>n'est pas chiffré</b> (la clef secrète y apparait en clair); Veuillez donc le stocker en lieu sûr !",
+        "EWIF_FORMAT": "Format EWIF (Encrypted Wallet Import Format) - v1",
+        "EWIF_FORMAT_HELP": "Ce format stocke votre trouseau <b>de manière chiffré</b> à partir d'une phrase secrète de votre choix. Il intègre aussi une somme de contrôle pour vérifier l'intégrité du fichier.<br/><b>Attention:</b> Veuillez à toujours vous rappeller de votre phrase secrète !",
         "PASSWORD_POPUP": {
           "TITLE": "Fichier de trousseau chiffré",
-          "HELP": "Veuillez indiquer le mot de passe:",
-          "PASSWORD_HELP": "Mot de passe"
+          "HELP": "Veuillez indiquer la phrase secrète:",
+          "PASSWORD_HELP": "Phrase secrète"
+        },
+        "ERROR": {
+          "BAD_PASSWORD": "Phrase secrète incorrecte"
         }
       }
     },
diff --git a/www/js/controllers/app-controllers.js b/www/js/controllers/app-controllers.js
index 0ff395cf3ddb4be922e2923e4b46c7be3012bc2c..95e70aa197ee788a29f3e5d0bec074ecf1be2074 100644
--- a/www/js/controllers/app-controllers.js
+++ b/www/js/controllers/app-controllers.js
@@ -86,37 +86,44 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
   // Device Methods
   ////////////////////////////////////////
 
-  function parseWif(data) {
-    return CryptoUtils.readWif(data, {
-        password: function() {
-          return Modals.showPassword({
+  function parseWIF(data, options) {
+    options = options || {};
+    options.withSecret = angular.isDefined(options.withSecret) && options.withSecret || true;
+    options.password = function() {
+        return Modals.showPassword({
             title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
-            subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
+            subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP',
+            error: options.error
           })
           .then(function(password) {
-            UIUtils.loading.show();
+            if (password) UIUtils.loading.show();
             return password;
           });
-        }
-      })
+      };
+
+    return CryptoUtils.parseWIF_or_EWIF(data, options)
       .catch(function(err) {
         if (err && err == 'CANCELLED') return;
-        if (err && err == 'BAD_PASSWORD') return parseWif(); // recursive call
+        if (err && err.ucode == CryptoUtils.errorCodes.BAD_PASSWORD) {
+          // recursive call
+          return parseWIF(data, {withSecret: options.withSecret, error: 'ACCOUNT.SECURITY.KEYFILE.ERROR.BAD_PASSWORD'});
+        }
         console.error("[app] Unable to parse as WIF or EWIF format: " + (err && err.message || err));
         throw err; // rethrow
       });
   }
 
   $scope.scanQrCodeAndGo = function() {
-    if (!Device.barcode.enable) {
-      return;
-    }
-    Device.barcode.scan()
+
+    if (!Device.barcode.enable) return;
+
+    // Run scan cordova plugin, on device
+    return Device.barcode.scan()
       .then(function(data) {
         if (!data) return;
 
-        // Parse as an URI
-        BMA.uri.parse(data)
+        // Try to parse as an URI
+        return BMA.uri.parse(data)
           .then(function(res){
             if (!res || res.pubkey) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
             // If pubkey: open the identity
@@ -131,15 +138,14 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
             console.debug(err && err.message || err);
 
             // Try to read as WIF format
-            return parseWif(data)
+            return parseWIF(data)
               .then(function(keypair) {
-                if (!keypair || !keypair.signPk || !keypair.signSk) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
-                var pubkey = CryptoUtils.base58.encode(keypair.signPk);
+                if (!keypair || !keypair.signPk || !keypair.signSk) throw err; // rethrow the first error
                 return csWallet.login({
                     forceAuth: true,
                     minData: false,
                     authData: {
-                      pubkey: pubkey,
+                      pubkey: CryptoUtils.base58.encode(keypair.signPk),
                       keypair: keypair
                     }
                   })
diff --git a/www/js/controllers/login-controllers.js b/www/js/controllers/login-controllers.js
index 34e250b18d1577dcb84fb32594d364914b978b24..00ba7f1851a7a177cce4e153277124024f10ed12 100644
--- a/www/js/controllers/login-controllers.js
+++ b/www/js/controllers/login-controllers.js
@@ -325,10 +325,11 @@ function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils,
     options = options || {};
 
     options.password = options.password || $scope.formData.file.password || function() {
-        $scope.formData.file.password = undefined;
+      $scope.formData.file.password = undefined;
       return Modals.showPassword({
             title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
-            subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
+            subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP',
+            error: options.error
           })
           .then(function (password) {
             // Remember password (for validation)
@@ -339,9 +340,10 @@ function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils,
 
     return CryptoUtils.readKeyFile($scope.formData.file, options)
       .catch(function(err) {
-        if (err && err == 'CANCELLED') return;
-        if (err && err == 'BAD_PASSWORD') {
-          return $scope.readKeyFile($scope.formData.file, options); // Loop (ask the password again)
+        $scope.formData.file.password = undefined;
+        if (err && err.ucode == CryptoUtils.errorCodes.BAD_PASSWORD) {
+          // Recursive call
+          return $scope.readKeyFile($scope.formData.file, {withSecret: options.withSecret, error: 'ACCOUNT.SECURITY.KEYFILE.ERROR.BAD_PASSWORD'});
         }
         throw err;
       });
diff --git a/www/js/services/crypto-services.js b/www/js/services/crypto-services.js
index 420cea95303eea69a21eb74787e22417bbed38da..ac15f9a3a1a890f5d6483c7e5fb1722423b87112 100644
--- a/www/js/services/crypto-services.js
+++ b/www/js/services/crypto-services.js
@@ -135,6 +135,11 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
       }
     };
 
+    CryptoAbstractService.prototype.errorCodes = {
+      BAD_PASSWORD: 3001,
+      BAD_CHECKSUM: 3002
+    };
+
     CryptoAbstractService.prototype.async_load_base58 = function(on_ready) {
       var that = this;
       if (Base58 !== null){return on_ready(Base58);}
@@ -235,7 +240,8 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
         if (!matches) {
           return $q.reject('Missing [Data] field in file. This is required for WIF or EWIF format');
         }
-        return that.readWif(matches[1], {
+
+        return that.parseWIF_or_EWIF(matches[1], {
             type: type,
             password: options.password
           })
@@ -253,7 +259,64 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
       }
     };
 
-    CryptoAbstractService.prototype.readWif_v1 = function(wif_base58) {
+
+    /**
+     *
+     * @param data_base58
+     * @param options
+     * @returns {*}
+     */
+    CryptoAbstractService.prototype.parseWIF_or_EWIF = function(data_base58, options) {
+      var that = this;
+      options = options || {};
+
+      var data_int8 = that.base58.decode(data_base58);
+      if (data_int8.length != that.constants.EWIF.DATA_LENGTH && data_int8.length != that.constants.WIF.DATA_LENGTH) {
+        return $q.reject('Invalid WIF or EWIF format (invalid bytes count).');
+      }
+
+      // Detect the type from the first byte
+      options.type = options.type || (data_int8[0] == 1 && 'WIF') || (data_int8[0] == 2 && 'EWIF');
+
+      // Type: WIF
+      if (options.type == 'WIF') {
+        return that.parseWIF_v1(data_base58);
+      }
+
+      // Type: EWIF
+      if (options.type == 'EWIF') {
+
+        // If not set, resolve password using the given callback
+        if (typeof options.password == "function") {
+          console.debug("[crypto] [EWIF] Executing 'options.password()' to resolve the password...");
+          options.password = options.password();
+          if (!options.password) {
+            return $q.reject({message: "Invalid callback result for 'options.password()': must return a promise or a string."});
+          }
+        }
+
+        // If password is a promise, get the result then read data
+        if (typeof options.password == "object" && options.password.then) {
+          return options.password.then(function(password) {
+            if (!password) throw 'CANCELLED';
+            return that.parseEWIF_v1(data_base58, password);
+          });
+        }
+
+        // If password is a valid string, read data
+        if (typeof options.password == "string") {
+          return that.parseEWIF_v1(data_base58, options.password);
+        }
+
+        return $q.reject({message: 'Invalid EWIF options.password. Waiting a callback function, a promise or a string.'});
+      }
+
+      // Unknown type
+      return $q.reject({message: 'Invalid WIF or EWIF format: unknown first byte identifier.'});
+    };
+
+
+    CryptoAbstractService.prototype.parseWIF_v1 = function(wif_base58) {
       var that = this,
         wif_int8 = that.util.decode_base58(wif_base58);
 
@@ -281,7 +344,7 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
       return that.seedKeypair(seed);
     };
 
-    CryptoAbstractService.prototype.readEwif_v1 = function(ewif_base58, password) {
+    CryptoAbstractService.prototype.parseEWIF_v1 = function(ewif_base58, password) {
       var that = this,
         ewif_int8 = that.util.decode_base58(ewif_base58);
 
@@ -341,13 +404,13 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
           // Check salt
           var expectedSalt = that.util.crypto_hash_sha256(that.util.crypto_hash_sha256(keypair.signPk)).slice(0,4);
           if(that.util.encode_base58(salt) !== that.util.encode_base58(expectedSalt)) {
-            throw 'BAD_PASSWORD';
+            throw {ucode: that.errorCodes.BAD_PASSWORD, message: 'ERROR.BAD_PASSWORD'};
           }
 
           // Check checksum
           var expectedChecksum = that.util.crypto_hash_sha256(that.util.crypto_hash_sha256(ewif_int8_no_checksum)).slice(0,2);
           if (that.util.encode_base58(checksum) != that.util.encode_base58(expectedChecksum)) {
-            throw {message: "Invalid EWIF format: bad checksum"};
+            throw {ucode: that.errorCodes.BAD_CHECKSUM, message: 'ERROR.BAD_CHECKSUM'};
           }
 
           return keypair;
@@ -355,77 +418,80 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
 
     };
 
-    /**
-     *
-     * @param data_base58
-     * @param options
-     * @returns {*}
-     */
-    CryptoAbstractService.prototype.readWif = function(data_base58, options) {
-      var that = this;
-      options = options || {};
+    CryptoAbstractService.prototype.pkChecksum = function(pubkey) {
+      var signPk_int8 = this.util.decode_base58(pubkey);
+      return this.util.encode_base58(this.util.crypto_hash_sha256(this.util.crypto_hash_sha256(signPk_int8))).substring(0,3);
+    };
 
-      // Check has password options, if EWIF or autodetect format
-      if ((!options.type || options.type === "EWIF") && !options.password) {
-        $q.reject("Missing options.password or options.passwordCallback");
-      }
+    CryptoAbstractService.prototype.seed_from_signSk = function(signSk) {
+      var that = this;
+      var seed = new Uint8Array(that.constants.SEED_LENGTH);
+      for (var i = 0; i < seed.length; i++) seed[i] = signSk[i];
+      return seed;
+    };
 
-      var data_int8 = that.base58.decode(data_base58);
-      if (data_int8.length != that.constants.EWIF.DATA_LENGTH && data_int8.length != that.constants.WIF.DATA_LENGTH) {
-        return $q.reject('Invalid WIF or EWIF format (invalid bytes count).');
-      }
+    CryptoAbstractService.prototype.generateKeyFileContent = function(keypair, options) {
+      var that = this;
+      options = options || {};
+      options.type = options.type || "PubSec";
+
+      switch(options.type) {
+
+        // PubSec
+        case "PubSec" :
+          return $q.resolve(
+            "Type: PubSec\n" +
+            "Version: 1\n" +
+            "pub: " + that.base58.encode(keypair.signPk) + "\n" +
+            "sec: " + that.base58.encode(keypair.signSk) + "\n");
+
+        // WIF - v1
+        case "WIF" :
+          return that.wif_v1_from_keypair(keypair)
+            .then(function(data) {
+              return "Type: WIF\n" +
+                "Version: 1\n" +
+                "Data: " + data + "\n";
+            });
 
-      // Detect the type from the first byte
-      options.type = options.type || (data_int8[0] == 1 && 'WIF') || (data_int8[0] == 2 && 'EWIF');
+        // EWIF - v1
+        case "EWIF" :
 
-      // Type: WIF
-      if (options.type == 'WIF') {
-        return that.readWif_v1(data_base58);
-      }
+          if (!options.password) return $q.reject({message: 'Missing EWIF options.password.'});
 
-      // Type: EWIF
-      if (options.type == 'EWIF') {
+          // If not set, resolve password using the given callback
+          if (options.password && typeof options.password == "function") {
+            console.debug("[crypto] [EWIF] Executing 'options.password()' to resolve the password...");
+            options.password = options.password();
+            if (!options.password) {
+              return $q.reject({message: "Invalid callback result for 'options.password()': must return a promise or a string."});
+            }
+          }
 
-        // If not set, resolve password using the given callback
-        if (typeof options.password == "function") {
-          console.debug("[crypto] [EWIF] Executing 'options.password()' to resolve the password...");
-          options.password = options.password();
-          if (!options.password) {
-            return $q.reject({message: "Invalid callback result for 'options.password()': must return a promise or a string."});
+          // If password is a promise, get the result then read data
+          if (options.password && typeof options.password == "object" && options.password.then) {
+            return options.password.then(function(password) {
+              if (!password) throw 'CANCELLED';
+              // Recursive call, with the string password in options
+              return that.generateKeyFileContent(keypair, angular.merge({}, options, {password: password}));
+            });
           }
-        }
 
-        // If password is a promise, get the result then read data
-        if (typeof options.password == "object" && options.password.then) {
-          return options.password.then(function(password) {
-            if (!password) throw 'CANCELLED';
-            return that.readEwif_v1(data_base58, password);
-          });
-        }
+          // If password is a valid string, read data
+          if (options.password && typeof options.password == "string") {
+            return that.ewif_v1_from_keypair(keypair, options.password)
+              .then(function(data) {
+                return "Type: EWIF\n" +
+                  "Version: 1\n" +
+                  "Data: " + data + "\n";
+              });
+          }
 
-        // If password is a valid string, read data
-        if (typeof options.password == "string") {
-          return that.readEwif_v1(data_base58, options.password);
-        }
+          return $q.reject({message: 'Invalid EWIF options.password. Waiting a callback function, a promise or a string.'});
 
-        return $q.reject({message: 'Invalid EWIF options.password. Waiting a callback function, a promise or a string.'});
+        default:
+          return $q.reject({message: "Unknown keyfile format: " + options.type});
       }
-
-      // Unknown type
-      return $q.reject({message: 'Invalid WIF or EWIF format: unknown first byte identifier.'});
-    };
-
-
-    CryptoAbstractService.prototype.pkChecksum = function(pubkey) {
-      var signPk_int8 = this.util.decode_base58(pubkey);
-      return this.util.encode_base58(this.util.crypto_hash_sha256(this.util.crypto_hash_sha256(signPk_int8))).substring(0,3);
-    };
-
-    CryptoAbstractService.prototype.seed_from_signSk = function(signSk) {
-      var that = this;
-      var seed = new Uint8Array(that.constants.SEED_LENGTH);
-      for (var i = 0; i < seed.length; i++) seed[i] = signSk[i];
-      return seed;
     };
 
     CryptoAbstractService.prototype.wif_v1_from_keypair = function(keypair) {
@@ -453,44 +519,47 @@ angular.module('cesium.crypto.services', ['cesium.utils.services'])
 
       var seed = that.seed_from_signSk(keypair.signSk);
       if (!seed || seed.byteLength !== that.constants.SEED_LENGTH)
-        throw "Bad see format. Expected {0} bytes".format(that.constants.SEED_LENGTH);
+        return $q.reject({message: "Bad see format. Expected {0} bytes".format(that.constants.SEED_LENGTH)});
 
       // salt
-      var salt = that.nacl.crypto_hash_sha256(that.nacl.crypto_hash_sha256(keypair.signPk)).slice(0,4);
+      var salt = that.util.crypto_hash_sha256(that.util.crypto_hash_sha256(keypair.signPk)).slice(0,4);
 
       // scrypt_seed
-      var scrypt_seed = that.util.crypto_scrypt(
+      return that.util.crypto_scrypt(
         that.util.encode_utf8(password),
         salt,
         that.constants.EWIF.SCRYPT_PARAMS.N,
         that.constants.EWIF.SCRYPT_PARAMS.r,
         that.constants.EWIF.SCRYPT_PARAMS.p,
-        64);
-      var derivedhalf1 = scrypt_seed.slice(0,32);
-      var derivedhalf2 = scrypt_seed.slice(32,64);
+        64)
+        .then(function(scrypt_seed) {
+          var derivedhalf1 = scrypt_seed.slice(0,32);
+          var derivedhalf2 = scrypt_seed.slice(32,64);
+
+          //XOR & AES
+          var seed1_xor_derivedhalf1_1 = xor(seed.slice(0,16), derivedhalf1.slice(0,16));
+          var seed2_xor_derivedhalf1_2 = xor(seed.slice(16,32), derivedhalf1.slice(16,32));
 
-      //XOR & AES
-      var seed1_xor_derivedhalf1_1 = xor(seed.slice(0,16), derivedhalf1.slice(0,16));
-      var seed2_xor_derivedhalf1_2 = xor(seed.slice(16,32), derivedhalf1.slice(16,32));
+          var aesEcb = new aesjs.ModeOfOperation.ecb(derivedhalf2);
+          var encryptedhalf1 = aesEcb.encrypt(seed1_xor_derivedhalf1_1);
+          var encryptedhalf2 = aesEcb.encrypt(seed2_xor_derivedhalf1_2);
 
-      var aesEcb = new aesjs.ModeOfOperation.ecb(derivedhalf2);
-      var encryptedhalf1 = aesEcb.encrypt(seed1_xor_derivedhalf1_1);
-      var encryptedhalf2 = aesEcb.encrypt(seed2_xor_derivedhalf1_2);
+          encryptedhalf1 = new Uint8Array(encryptedhalf1);
+          encryptedhalf2 = new Uint8Array(encryptedhalf2);
 
-      encryptedhalf1 = new Uint8Array(encryptedhalf1);
-      encryptedhalf2 = new Uint8Array(encryptedhalf2);
+          // concatenate ewif
+          var ewif_int8 = new Uint8Array(1);
+          ewif_int8[0] = 0x02;
+          ewif_int8 = concat_Uint8Array(ewif_int8,salt);
+          ewif_int8 = concat_Uint8Array(ewif_int8,encryptedhalf1);
+          ewif_int8 = concat_Uint8Array(ewif_int8,encryptedhalf2);
 
-      // concatenate ewif
-      var ewif_int8 = new Uint8Array(1);
-      ewif_int8[0] = 0x02;
-      ewif_int8 = concat_Uint8Array(ewif_int8,salt);
-      ewif_int8 = concat_Uint8Array(ewif_int8,encryptedhalf1);
-      ewif_int8 = concat_Uint8Array(ewif_int8,encryptedhalf2);
+          var checksum = that.util.crypto_hash_sha256(that.util.crypto_hash_sha256(ewif_int8)).slice(0,2);
+          ewif_int8 = concat_Uint8Array(ewif_int8,checksum);
 
-      var checksum = that.nacl.crypto_hash_sha256(that.nacl.crypto_hash_sha256(ewif_int8)).slice(0,2);
-      ewif_int8 = concat_Uint8Array(ewif_int8,checksum);
+          return that.util.encode_base58(ewif_int8);
+      });
 
-      return that.util.encode_base58(ewif_int8);
     };
 
     // Web crypto API - see https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API
diff --git a/www/js/services/modal-services.js b/www/js/services/modal-services.js
index e6aff2dafde9f21293dd6bf2b263235e34792c3f..61614948306a550cb556795af1d03c9704322e1e 100644
--- a/www/js/services/modal-services.js
+++ b/www/js/services/modal-services.js
@@ -146,7 +146,7 @@ angular.module('cesium.modal.services', [])
   };
 })
 
-.factory('Modals', function($rootScope, $translate, $ionicPopup, ModalUtils, UIUtils) {
+.factory('Modals', function($rootScope, $translate, $ionicPopup, $timeout, ModalUtils, UIUtils) {
   'ngInject';
 
   function showTransfer(parameters) {
@@ -235,14 +235,14 @@ angular.module('cesium.modal.services', [])
     };
     scope.submit = function(e) {
       scope.form.$submitted=true;
-      if(!scope.form.$valid || !scope.formData.password) {
-        //don't allow the user to close unless he enters a uid
-        if (e && e.preventDefault) e.preventDefault();
-      } else {
+      if (e && e.preventDefault) e.preventDefault();
+      if(scope.form.$valid && scope.formData.password) {
         options.popup.close(scope.formData.password);
       }
     };
 
+    scope.error = options.error || undefined;
+
     // Choose password popup
     return $translate([options.title, options.subTitle, 'COMMON.BTN_OK', 'COMMON.BTN_CANCEL'])
       .then(function (translations) {
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index 58105e45af6ebb73a7dd91f9a477fc5b0e221816..82de629a4b670438734824d669fcfc625fb885e9 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -1409,41 +1409,30 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
     },
 
-    getKeyFileDocument =function(format) {
-
-      var document;
-      switch(format) {
-        case "PubSec" :
-          document = "Type: PubSec\n" +
-            "Version: 1\n" +
-            "pub: " + data.pubkey + "\n" +
-            "sec: " + CryptoUtils.base58.encode(data.keypair.signSk) + "\n";
-          break;
-        case "WIF" :
-          document = "Type: WIF\n" +
-            "Version: 1\n" +
-            "Data: " + CryptoUtils.wif_v1_from_keypair(data.keypair)+ "\n";
-          break;
-        case "EWIF" :
-          document = "Type: EWIF\n" +
-            "Version: 1\n" +
-            "Data: " + CryptoUtils.ewif_v1_from_keypair(data.keypair, "bonjour") + "\n";
-          break;
-        default:
-          return $q.reject("Unknown keyfile format: " + format);
-      }
 
-      if (document) {
-        return $q.resolve(document);
-      }
-    },
 
     downloadKeyFile = function(format){
       if (!isAuth()) return $q.reject('user not authenticated');
 
       return $q.all([
           csCurrency.get(),
-          getKeyFileDocument(format)
+          CryptoUtils.generateKeyFileContent(data.keypair,
+            {
+              type: format,
+              password: function() {
+                UIUtils.loading.hide();
+                return Modals.showPassword({
+                    title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
+                    subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
+                  })
+                  .then(function(password) {
+                    return UIUtils.loading.show(10)
+                      .then(function(){
+                        return password;
+                    });
+                  });
+              }
+          })
         ])
         .then(function(res) {
           var currency = res[0];
diff --git a/www/templates/common/popup_password.html b/www/templates/common/popup_password.html
index 800e93b14f4831e4bab24ccc9acde69facdf0359..f957bc659134dcabecb974e21909b35eeccdcd49 100644
--- a/www/templates/common/popup_password.html
+++ b/www/templates/common/popup_password.html
@@ -17,5 +17,8 @@
         <span translate="ERROR.FIELD_TOO_SHORT"></span>
       </div>
     </div>
+    <div class="form-errors" ng-if="error">
+      <div class="form-error" >{{error|translate}}</div>
+    </div>
   </div>
 </form>